mirror of
https://github.com/nicolargo/glances.git
synced 2024-11-28 05:42:57 +03:00
Server password configuration for the browser mode #500
This commit is contained in:
parent
5e4c51652c
commit
4f41d8c062
4
NEWS
4
NEWS
@ -5,7 +5,9 @@ Glances Version 2.x
|
||||
Version 2.5
|
||||
===========
|
||||
|
||||
...
|
||||
Enhancements and new features:
|
||||
|
||||
* Server password configuration for the browser mode (issue #500)
|
||||
|
||||
Version 2.4.2
|
||||
=============
|
||||
|
@ -153,7 +153,7 @@ mem_critical=90
|
||||
#list_3_countmin=1
|
||||
|
||||
#[serverlist]
|
||||
# Define the static server list
|
||||
# Define the static servers list
|
||||
#server_1_name=localhost
|
||||
#server_1_alias=My local PC
|
||||
#server_1_port=61209
|
||||
@ -165,6 +165,15 @@ mem_critical=90
|
||||
#server_4_name=pasbon
|
||||
#server_4_port=61237
|
||||
|
||||
[passwords]
|
||||
# Define the passwords list
|
||||
# Syntax: host=password
|
||||
# Where: host is the hostname
|
||||
# password is the clear password
|
||||
# Additionnaly (and optionnaly) a default password could be defined
|
||||
#xps=abc
|
||||
#default=defaultpassword
|
||||
|
||||
[influxdb]
|
||||
host=localhost
|
||||
port=8086
|
||||
|
@ -27,12 +27,14 @@ try:
|
||||
except ImportError:
|
||||
# Python 2
|
||||
from xmlrpclib import ServerProxy, Fault, ProtocolError
|
||||
from hashlib import sha256
|
||||
|
||||
# Import Glances libs
|
||||
from glances.core.glances_autodiscover import GlancesAutoDiscoverServer
|
||||
from glances.core.glances_client import GlancesClient, GlancesClientTransport
|
||||
from glances.core.glances_logging import logger
|
||||
from glances.core.glances_staticlist import GlancesStaticServer
|
||||
from glances.core.glances_passwordlist import GlancesPassword
|
||||
from glances.outputs.glances_curses import GlancesCursesBrowser
|
||||
|
||||
|
||||
@ -44,9 +46,11 @@ class GlancesClientBrowser(object):
|
||||
# Store the arg/config
|
||||
self.args = args
|
||||
self.config = config
|
||||
self.static_server = None
|
||||
self.password = None
|
||||
|
||||
# Init the static server list (if defined)
|
||||
self.static_server = GlancesStaticServer(config=self.config)
|
||||
# Load the configuration file
|
||||
self.load()
|
||||
|
||||
# Start the autodiscover mode (Zeroconf listener)
|
||||
if not self.args.disable_autodiscover:
|
||||
@ -57,6 +61,14 @@ class GlancesClientBrowser(object):
|
||||
# Init screen
|
||||
self.screen = GlancesCursesBrowser(args=self.args)
|
||||
|
||||
def load(self):
|
||||
"""Load server and password list from the confiuration file"""
|
||||
# Init the static server list (if defined)
|
||||
self.static_server = GlancesStaticServer(config=self.config)
|
||||
|
||||
# Init the password list (if defined)
|
||||
self.password = GlancesPassword(config=self.config)
|
||||
|
||||
def get_servers_list(self):
|
||||
"""Return the current server list (list of dict).
|
||||
|
||||
@ -75,6 +87,11 @@ class GlancesClientBrowser(object):
|
||||
"""Return the URI for the given server dict."""
|
||||
# Select the connection mode (with or without password)
|
||||
if server['password'] != "":
|
||||
if server['status'] == 'PROTECTED':
|
||||
# Try with the preconfigure password (only if status is PROTECTED)
|
||||
clear_password = self.password.get_password(server['name'])
|
||||
if clear_password is not None:
|
||||
server['password'] = self._encode_password(clear_password)
|
||||
return 'http://{0}:{1}@{2}:{3}'.format(server['username'], server['password'],
|
||||
server['ip'], server['port'])
|
||||
else:
|
||||
@ -165,14 +182,17 @@ class GlancesClientBrowser(object):
|
||||
|
||||
# A password is needed to access to the server's stats
|
||||
if self.get_servers_list()[self.screen.active_server]['password'] is None:
|
||||
from hashlib import sha256
|
||||
# Display a popup to enter password
|
||||
clear_password = self.screen.display_popup(
|
||||
'Password needed for {0}: '.format(v['name']), is_input=True)
|
||||
# Hash with SHA256
|
||||
encoded_password = sha256(clear_password.encode('utf-8')).hexdigest()
|
||||
# First of all, check if a password is available in the [passwords] section
|
||||
clear_password = self.password.get_password(v['name'])
|
||||
if clear_password is None \
|
||||
or self.get_servers_list()[self.screen.active_server]['status'] == 'PROTECTED':
|
||||
# Else, the password should be enter by the user
|
||||
# Display a popup to enter password
|
||||
clear_password = self.screen.display_popup(
|
||||
'Password needed for {0}: '.format(v['name']), is_input=True)
|
||||
# Store the password for the selected server
|
||||
self.set_in_selected('password', encoded_password)
|
||||
self.set_in_selected('password',
|
||||
self._encode_password(clear_password))
|
||||
|
||||
# Display the Glance client on the selected server
|
||||
logger.info("Connect Glances client to the {0} server".format(
|
||||
@ -238,6 +258,11 @@ class GlancesClientBrowser(object):
|
||||
else:
|
||||
self.static_server.set_server(self.screen.active_server, key, value)
|
||||
|
||||
def _encode_password(self, clear_password):
|
||||
"""Encode clear password using SHA256"""
|
||||
# Hash with SHA256
|
||||
return sha256(clear_password.encode('utf-8')).hexdigest()
|
||||
|
||||
def end(self):
|
||||
"""End of the client browser session."""
|
||||
self.screen.end()
|
||||
|
76
glances/core/glances_passwordlist.py
Normal file
76
glances/core/glances_passwordlist.py
Normal file
@ -0,0 +1,76 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2015 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Manage the Glances passwords list."""
|
||||
|
||||
# Import Glances libs
|
||||
from glances.core.glances_logging import logger
|
||||
|
||||
|
||||
class GlancesPassword(object):
|
||||
|
||||
"""Manage the Glances passwords list for the client|browser/server."""
|
||||
|
||||
_section = "passwords"
|
||||
|
||||
def __init__(self, config=None, args=None):
|
||||
# password_dict is a dict (JSON compliant)
|
||||
# {'host': 'password', ... }
|
||||
# Load the configuration file
|
||||
self._password_dict = self.load(config)
|
||||
|
||||
def load(self, config):
|
||||
"""Load the password from the configuration file."""
|
||||
password_dict = []
|
||||
|
||||
if config is None:
|
||||
logger.warning("No configuration file available. Cannot load password list.")
|
||||
elif not config.has_section(self._section):
|
||||
logger.warning("No [%s] section in the configuration file. Cannot load password list." % self._section)
|
||||
else:
|
||||
logger.info("Start reading the [%s] section in the configuration file" % self._section)
|
||||
|
||||
password_dict = dict(config.items(self._section))
|
||||
|
||||
# Password list loaded
|
||||
logger.info("%s password(s) loaded from the configuration file" % len(password_dict))
|
||||
logger.debug("Password dictionary: %s" % password_dict)
|
||||
|
||||
return password_dict
|
||||
|
||||
def get_password(self, host=None):
|
||||
"""
|
||||
If host=None, return the current server list (dict).
|
||||
Else, return the host's password (or the default one if defined or None)
|
||||
"""
|
||||
if host is None:
|
||||
return self._password_dict
|
||||
else:
|
||||
try:
|
||||
return self._password_dict[host]
|
||||
except (KeyError, TypeError):
|
||||
try:
|
||||
return self._password_dict['default']
|
||||
except (KeyError, TypeError):
|
||||
return None
|
||||
return None
|
||||
|
||||
def set_password(self, host, password):
|
||||
"""Set a password for a specific host."""
|
||||
self._password_dict[host] = password
|
@ -59,6 +59,7 @@ class GlancesStaticServer(object):
|
||||
if new_server['port'] is None:
|
||||
new_server['port'] = 61209
|
||||
new_server['username'] = 'glances'
|
||||
# By default, try empty (aka no) password
|
||||
new_server['password'] = ''
|
||||
try:
|
||||
new_server['ip'] = gethostbyname(new_server['name'])
|
||||
|
@ -1089,7 +1089,7 @@ class GlancesCursesBrowser(_GlancesCurses):
|
||||
['load_min5', 'LOAD', 6],
|
||||
['cpu_percent', 'CPU%', 5],
|
||||
['mem_percent', 'MEM%', 5],
|
||||
['status', 'STATUS', 8],
|
||||
['status', 'STATUS', 9],
|
||||
['ip', 'IP', 15],
|
||||
# ['port', 'PORT', 5],
|
||||
['hr_name', 'OS', 16],
|
||||
|
Loading…
Reference in New Issue
Block a user