Issue #96 Authentication fields for website/services

- File functions.inc.php - modified and added features psm_curl_get parameters for website_username and website_password
- File functions.inc.php - new features and psm_password_encrypt psm_password_decrypt to encrypt and decrypt passwords
- Adjusted basic language EN and supplemented by new language CZ phrase
- ConfigController.php - adjusted executeIndex method of password encryption key for each installation separately + executeSave method of saving the settings + added labels to methods getLabels
- AbstractServerController.php - adjusted method getServers a login password of the name
- ServerController.php - adjusted executeEdit method for storing information about name and password + executeSave method of storage in a database + method getLabels on labels
- Installer.php - adjusted method install a new configuration values ​​for the encryption key passwords + method installTables a new table structure servers + method upgrade320 the new structure
- StatusUpdater.php - adjusted method update the transmission website_username and website_password + method updateWebsite adjusted parameters passed to the function psm_curl_get
- Modified template: config/config.tpl.html, server/update.tpl.html, view.tpl.html
- Adapted javascript scripts.js
This commit is contained in:
Pavel Dvořák 2016-05-21 16:53:51 +02:00
parent fb131b843a
commit 340660da4b
12 changed files with 210 additions and 14 deletions

View File

@ -291,9 +291,11 @@ function psm_parse_msg($status, $type, $vars) {
* @param boolean $body return body?
* @param int $timeout connection timeout in seconds. defaults to PSM_CURL_TIMEOUT (10 secs).
* @param boolean $add_agent add user agent?
* @param string|bool $website_username Username website
* @param string|bool $website_password Password website
* @return string cURL result
*/
function psm_curl_get($href, $header = false, $body = true, $timeout = null, $add_agent = true) {
function psm_curl_get($href, $header = false, $body = true, $timeout = null, $add_agent = true, $website_username = false, $website_password = false) {
$timeout = $timeout == null ? PSM_CURL_TIMEOUT : intval($timeout);
$ch = curl_init();
@ -306,7 +308,13 @@ function psm_curl_get($href, $header = false, $body = true, $timeout = null, $ad
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_ENCODING, '');
if($website_username !== false && $website_password !== false && !empty($website_username) && !empty($website_password)) {
curl_setopt($ch, CURLOPT_USERPWD, $website_username . ":" . $website_password);
}
curl_setopt($ch, CURLOPT_URL, $href);
if($add_agent) {
curl_setopt ($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; phpservermon/'.PSM_VERSION.'; +http://www.phpservermonitor.org)');
}
@ -611,4 +619,62 @@ function psm_no_cache() {
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
}
/**
* Encrypts the password for storage in the database
*
* @param string $password
* @return string
* @author Pavel Laupe Dvorak <pavel@pavel-dvorak.cz>
*/
function psm_password_encrypt($password)
{
$key = psm_get_conf('password_encrypt_key');
$iv = mcrypt_create_iv(
mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC),
MCRYPT_DEV_URANDOM
);
$encrypted = base64_encode(
$iv .
mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
hash('sha256', $key, true),
$password,
MCRYPT_MODE_CBC,
$iv
)
);
return $encrypted;
}
/**
* Decrypts password stored in the database for future use
*
* @param string $encryptedString
* @return string
* @author Pavel Laupe Dvorak <pavel@pavel-dvorak.cz>
*/
function psm_password_decrypt($encryptedString)
{
$key = psm_get_conf('password_encrypt_key');
$data = base64_decode($encryptedString);
$iv = substr($data, 0, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC));
$decrypted = rtrim(
mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
hash('sha256', $key, true),
substr($data, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC)),
MCRYPT_MODE_CBC,
$iv
),
"\0"
);
return $decrypted;
}

View File

@ -122,6 +122,13 @@ $sm_lang = array(
'domain' => 'Doména/IP',
'timeout' => 'Časový limit',
'timeout_description' => 'Počet vteřin čekání na odpověď serveru.',
'authentication_settings' => 'Nastavení autentizace (volitelný)',
'website_username' => 'Uživatelské jméno',
'website_username_description' => 'Uživatelské jméno pro přístup na stránku. (Pouze Apache autorizace je podporovaná.)',
'website_password' => 'Heslo',
'website_password_description' => 'Heslo pro přístup na stránku. Heslo je v databázi šifrované a NENÍ uloženo v čistém textu.',
'fieldset_monitoring' => 'Monitoring',
'fieldset_permissions' => 'Oprávnění',
'port' => 'Port',
'custom_port' => 'Uživatelský Port',
'popular_ports' => 'Populární Porty',
@ -180,6 +187,8 @@ $sm_lang = array(
'general' => 'Obecné',
'language' => 'Jazyk',
'show_update' => 'Kontrolovat aktualizace?',
'password_encrypt_key' => 'Šifrovací klíč pro hesla',
'password_encrypt_key_note' => 'Tímto klíčem se šifrují hesla, která se ukládají u serverů pro přístup na webové stránky. Pokud klíč změníte budou uložená hesla neplatná!',
'email_status' => 'Povolit odesílání e-mailu',
'email_from_email' => 'E-mailová adresa odesilatele',
'email_from_name' => 'Jméno odesilatele',

View File

@ -121,6 +121,13 @@ $sm_lang = array(
'domain' => 'Domain/IP',
'timeout' => 'Timeout',
'timeout_description' => 'Number of seconds to wait for the server to respond.',
'authentication_settings' => 'Authentication Settings (Optional)',
'website_username' => 'Username',
'website_username_description' => 'Username to access the site. (Only Apache authentication is supported.)',
'website_password' => 'Password',
'website_password_description' => 'Password to access the site. The password is encrypted in the database and is not stored in plain text.',
'fieldset_monitoring' => 'Monitoring',
'fieldset_permissions' => 'Permissions',
'port' => 'Port',
'custom_port' => 'Custom Port',
'popular_ports' => 'Popular Ports',
@ -179,6 +186,8 @@ $sm_lang = array(
'general' => 'General',
'language' => 'Language',
'show_update' => 'Check for updates?',
'password_encrypt_key' => 'The encryption key password',
'password_encrypt_key_note' => 'This key is used to encrypt passwords that are stored on servers for access to websites. If the key will change the stored password is invalid!',
'email_status' => 'Allow sending email',
'email_from_email' => 'Email from address',
'email_from_name' => 'Email from name',

View File

@ -117,6 +117,7 @@ class ConfigController extends AbstractController {
$tpl_data['email_smtp_security_selected_' . $smtp_sec] = 'selected="selected"';
$tpl_data['auto_refresh_servers'] = (isset($config['auto_refresh_servers'])) ? $config['auto_refresh_servers'] : '0';
$tpl_data['log_retention_period'] = (isset($config['log_retention_period'])) ? $config['log_retention_period'] : '365';
$tpl_data['password_encrypt_key'] = (isset($config['password_encrypt_key'])) ? $config['password_encrypt_key'] : sha1(microtime());
foreach($this->checkboxes as $input_key) {
$tpl_data[$input_key . '_checked'] =
@ -159,6 +160,7 @@ class ConfigController extends AbstractController {
: '',
'auto_refresh_servers' => intval(psm_POST('auto_refresh_servers', 0)),
'log_retention_period' => intval(psm_POST('log_retention_period', 365)),
'password_encrypt_key' => psm_POST('password_encrypt_key', sha1(microtime())),
);
foreach($this->checkboxes as $input_key) {
$clean[$input_key] = (isset($_POST[$input_key])) ? '1': '0';
@ -294,6 +296,8 @@ class ConfigController extends AbstractController {
'label_general' => psm_get_lang('config', 'general'),
'label_language' => psm_get_lang('config', 'language'),
'label_show_update' => psm_get_lang('config', 'show_update'),
'label_password_encrypt_key' => psm_get_lang('config', 'password_encrypt_key'),
'label_password_encrypt_key_note' => psm_get_lang('config', 'password_encrypt_key_note'),
'label_email_status' => psm_get_lang('config', 'email_status'),
'label_email_from_email' => psm_get_lang('config', 'email_from_email'),
'label_email_from_name' => psm_get_lang('config', 'email_from_name'),

View File

@ -75,7 +75,9 @@ abstract class AbstractServerController extends AbstractController {
`s`.`pushover`,
`s`.`warning_threshold`,
`s`.`warning_threshold_counter`,
`s`.`timeout`
`s`.`timeout`,
`s`.`website_username`,
`s`.`website_password`
FROM `".PSM_DB_PREFIX."servers` AS `s`
{$sql_join}
{$sql_where}

View File

@ -199,6 +199,8 @@ class ServerController extends AbstractServerController {
'default_value_timeout' => PSM_CURL_TIMEOUT,
'edit_value_pattern' => $edit_server['pattern'],
'edit_value_warning_threshold' => $edit_server['warning_threshold'],
'edit_website_username' => $edit_server['website_username'],
'edit_website_password' => psm_password_decrypt($edit_server['website_password']),
'edit_type_selected_' . $edit_server['type'] => 'selected="selected"',
'edit_active_selected_' . $edit_server['active'] => 'selected="selected"',
'edit_email_selected_' . $edit_server['email'] => 'selected="selected"',
@ -235,6 +237,8 @@ class ServerController extends AbstractServerController {
'label' => trim(strip_tags(psm_POST('label', ''))),
'ip' => trim(strip_tags(psm_POST('ip', ''))),
'timeout' => (isset($_POST['timeout']) && intval($_POST['timeout']) > 0) ? intval($_POST['timeout']) : null,
'website_username' => psm_POST('website_username', null),
'website_password' => (isset($_POST['website_password'])) ? psm_password_encrypt(psm_POST('website_password')) : '',
'port' => intval(psm_POST('port', 0)),
'type' => psm_POST('type', ''),
'pattern' => psm_POST('pattern', ''),
@ -390,6 +394,13 @@ class ServerController extends AbstractServerController {
'label_domain' => psm_get_lang('servers', 'domain'),
'label_timeout' => psm_get_lang('servers', 'timeout'),
'label_timeout_description' => psm_get_lang('servers', 'timeout_description'),
'label_authentication_settings' => psm_get_lang('servers', 'authentication_settings'),
'label_website_username' => psm_get_lang('servers', 'website_username'),
'label_website_username_description' => psm_get_lang('servers', 'website_username_description'),
'label_website_password' => psm_get_lang('servers', 'website_password'),
'label_website_password_description' => psm_get_lang('servers', 'website_password_description'),
'label_fieldset_monitoring' => psm_get_lang('servers', 'fieldset_monitoring'),
'label_fieldset_permissions' => psm_get_lang('servers', 'fieldset_permissions'),
'label_port' => psm_get_lang('servers', 'port'),
'label_custom_port' => psm_get_lang('servers', 'custom_port'),
'label_please_select' => psm_get_lang('servers', 'please_select'),

View File

@ -146,6 +146,7 @@ class Installer {
('sms_from', '1234567890'),
('pushover_status', '0'),
('pushover_api_token', ''),
('password_encrypt_key', " . sha1(microtime()) . "),
('alert_type', 'status'),
('log_status', '1'),
('log_email', '1'),
@ -227,6 +228,8 @@ class Installer {
`warning_threshold` mediumint(1) unsigned NOT NULL DEFAULT '1',
`warning_threshold_counter` mediumint(1) unsigned NOT NULL DEFAULT '0',
`timeout` smallint(1) unsigned NULL DEFAULT NULL,
`website_username` varchar(255) DEFAULT NULL,
`website_password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`server_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;",
PSM_DB_PREFIX . 'servers_uptime' => "CREATE TABLE IF NOT EXISTS `" . PSM_DB_PREFIX . "servers_uptime` (
@ -398,6 +401,9 @@ class Installer {
$this->execSQL("ALTER TABLE `".PSM_DB_PREFIX."users` DROP `server_id`;");
}
/**
* Upgrade for v3.1.0 release
*/
protected function upgrade310() {
$queries = array();
psm_update_conf('log_retention_period', '365');
@ -423,10 +429,15 @@ class Installer {
$this->execSQL($queries);
}
/**
* Upgrade for v3.2.0 release
*/
protected function upgrade320() {
$queries = array();
psm_update_conf('password_encrypt_key', sha1(microtime()));
$queries[] = "ALTER TABLE `" . PSM_DB_PREFIX . "servers` CHANGE `ip` `ip` VARCHAR(500) NOT NULL;";
$queries[] = "ALTER TABLE `" . PSM_DB_PREFIX . "servers` ADD `website_username` varchar(255) NULL, ADD `website_password` varchar(255) NULL AFTER `website_username`;";
$this->execSQL($queries);
}

View File

@ -82,7 +82,8 @@ class StatusUpdater {
$this->server = $this->db->selectRow(PSM_DB_PREFIX . 'servers', array(
'server_id' => $server_id,
), array(
'server_id', 'ip', 'port', 'label', 'type', 'pattern', 'status', 'active', 'warning_threshold', 'warning_threshold_counter', 'timeout',
'server_id', 'ip', 'port', 'label', 'type', 'pattern', 'status', 'active', 'warning_threshold',
'warning_threshold_counter', 'timeout', 'website_username', 'website_password'
));
if(empty($this->server)) {
return false;
@ -176,7 +177,10 @@ class StatusUpdater {
$this->server['ip'],
true,
($this->server['pattern'] == '' ? false : true),
$this->server['timeout']
$this->server['timeout'],
true,
$this->server['website_username'],
psm_password_decrypt($this->server['website_password'])
);
$this->rtime = (microtime(true) - $starttime);

View File

@ -31,7 +31,17 @@
<input type="text" class="input-mini" id="auto_refresh_servers" name="auto_refresh_servers" value="{{ auto_refresh_servers }}" maxlength="10" data-toggle="tooltip" title="{{ label_auto_refresh_servers }}" />&nbsp;{{ label_seconds }}
</div>
</div>
</fieldset>
<div class="control-group">
<label class="control-label" for="password_encrypt_key">
{{ label_password_encrypt_key }}
</label>
<div class="controls">
<input type="text" class="input-xxlarge" id="password_encrypt_key" name="password_encrypt_key"
value="{{ password_encrypt_key }}" maxlength="40" data-toggle="tooltip"
title="{{ label_password_encrypt_key_note }}"/>
</div>
</div>
</fieldset>
<fieldset>
<legend>{{ label_settings_notification }}</legend>
<div class="control-group">

View File

@ -19,12 +19,13 @@
<label class="control-label" for="type">{{ label_type }}</label>
<div class="controls">
<select id="type" name="type">
<option value="">{{ label_please_select }}</option>
<option value="service" {{ edit_type_selected_service|raw }}>{{ label_service }}</option>
<option value="website" {{ edit_type_selected_website|raw }}>{{ label_website }}</option>
</select>
</div>
</div>
<div class="control-group popularPortsGroup">
<div class="control-group popularPortsGroup types typeService">
<label class="control-label" for="popularPorts">{{ label_port }}</label>
<div class="controls">
<select id="popularPorts" name="popularPorts">
@ -50,30 +51,50 @@
</select>
</div>
</div>
<div class="control-group portGroup">
<div class="control-group portGroup types typeService">
<label class="control-label" for="port">{{ label_custom_port }}</label>
<div class="controls">
<input class="input-mini" type="text" id="port" name="port" value="{{ edit_value_port }}" maxlength="5" />
</div>
</div>
<div class="control-group">
<div class="control-group types typeWebsite">
<label class="control-label" for="pattern">{{ label_pattern }}</label>
<div class="controls">
<input type="text" id="pattern" name="pattern" value="{{ edit_value_pattern }}" maxlength="255" data-toggle="tooltip" title="{{ label_pattern_description }}" />
</div>
</div>
<div class="control-group">
<div class="control-group types typeWebsite">
<label class="control-label" for="warning_threshold">{{ label_warning_threshold }}</label>
<div class="controls">
<input class="input-mini" type="text" id="warning_threshold" name="warning_threshold" value="{{ edit_value_warning_threshold }}" maxlength="5" data-toggle="tooltip" title="{{ label_warning_threshold_description }}" />
</div>
</div>
<div class="control-group">
<div class="control-group types typeWebsite">
<label class="control-label" for="timeout">{{ label_timeout }}</label>
<div class="controls">
<input class="input-mini" type="text" id="timeout" name="timeout" value="{{ edit_value_timeout }}" placeholder="{{ default_value_timeout }}" maxlength="10" data-toggle="tooltip" title="{{ label_timeout_description }}" /> s
</div>
</div>
</fieldset>
<fieldset>
<legend class="types typeWebsite">{{ label_authentication_settings}}</legend>
<div class="control-group types typeWebsite">
<label class="control-label" for="website_username">{{ label_website_username }}</label>
<div class="controls">
<input type="text" id="website_username" name="website_username" value="{{ edit_website_username }}" data-toggle="tooltip" title="{{ label_website_username_description }}" />
</div>
</div>
<div class="control-group types typeWebsite">
<label class="control-label" for="website_password">{{ label_website_password }}</label>
<div class="controls">
<input type="text" id="website_password" name="website_password" value="{{ edit_website_password }}" data-toggle="tooltip" title="{{ label_website_password_description }}" />
</div>
</div>
</fieldset>
<fieldset>
<legend>{{ label_fieldset_monitoring }}</legend>
<div class="control-group">
<label class="control-label" for="active">{{ label_monitoring }}</label>
<div class="controls">
@ -116,6 +137,10 @@
</select>
</div>
</div>
</fieldset>
<fieldset>
<legend>{{ label_fieldset_permissions }}</legend>
<div class="control-group">
<label class="control-label" for="user_id">{{ label_users }}</label>
<div class="controls">

View File

@ -73,6 +73,14 @@
<td>{{ label_timeout }}:</td>
<td>{{ timeout }} s</td>
</tr>
<tr>
<td>{{ label_website_username }}:</td>
<td>{{ website_username }}</td>
</tr>
<tr>
<td>{{ label_website_password }}:</td>
<td>******</td>
</tr>
{% if has_admin_actions %}
<tr>
<td class="hidden-small">&nbsp;</td>

View File

@ -56,7 +56,6 @@ $().ready(function() {
if (portInput != '') {
var findPopularPorts = $('#popularPorts').find('option[value=' + portInput + ']');
if(findPopularPorts.length) {
$(findPopularPorts).attr("selected", "selected");
} else {
@ -66,16 +65,54 @@ $().ready(function() {
}
$('#popularPorts').change(function () {
var popularPorts = $(this).val();
changePopularPorts($(this).val(), false, $('#type').val());
});
// server type
$('.types').hide();
changeTypeSwitch($('#type').val());
$('#type').change(function () {
changeTypeSwitch($('#type').val());
changePopularPorts($('#popularPorts').val(), true, $('#type').val());
});
});
function changeTypeSwitch(typeInput) {
switch (typeInput) {
case 'service':
$('.types').slideUp();
$('.typeService').slideDown();
break;
case 'website':
$('.types').slideUp();
$('.typeWebsite').slideDown();
break;
default:
$('.types').hide();
}
}
function changePopularPorts(popularPorts, changeType, typeInput) {
if (changeType === true) {
if (typeInput == 'service') {
if (popularPorts == 'custom') {
$('.portGroup').slideDown();
} else {
$('.portGroup').hide();
}
}
} else {
if (popularPorts == 'custom') {
$('.portGroup').slideDown();
} else {
$('#port').val(popularPorts);
$('.portGroup').slideUp();
}
});
});
}
}
function psm_xhr(mod, params, method, on_complete, options) {
method = (typeof method == 'undefined') ? 'GET' : method;