def validate_password(self, realm, username, password): """ Validate a given user/password combination :param realm: :param username: :param password: :return: """ pwd_hash = Utils.create_hash(password) # self.logger.warning("realm: {}, username: {}, password: {}, self._password: {}, self._hashed_password: {}".format(realm, username, password, self._password, self._hashed_password)) # self.logger.warning("pwd_hash: {}, self._user_dict: {}".format(pwd_hash, self._user_dict)) user = self._user_dict.get(username, None) if user is None: return False; user_pwd_hash = user.get('password_hash', '') pwd_hash = Utils.create_hash(password) return pwd_hash == user_pwd_hash
def test_create_hash(self): with self.assertRaises(Exception): Utils.create_hash(None) self.assertEqual(Utils.create_hash(''), 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e') self.assertEqual(Utils.create_hash('42'), '39ca7ce9ecc69f696bf7d20bb23dd1521b641f806cc7a6b724aaa6cdbffb3a023ff98ae73225156b2c6c9ceddbfc16f5453e8fa49fc10e5d96a3885546a46ef4') self.assertEqual(Utils.create_hash('very_secure_password'), '1245a9633edf47b7091f37c4d294b5be5a9936c81c5359b16d1c4833729965663f1943ef240959c53803fedef7ac19bd59c66ad7e7092d7dbf155ce45884607d') self.assertEqual(Utils.create_hash('1245a9633edf47b7091f37c4d294b5be5a9936c81c5359b16d1c4833729965663f1943ef240959c53803fedef7ac19bd59c66ad7e7092d7dbf155ce45884607d'), '00faf4a142f087e55edf6e91ea333d9a4bcd9b2d6bba8fab42869c6e00e28a3acba6d5fe3495f037221d633e01b3c7baa6e915028407548f77b5b9710899bfbe')
def authenticate(self): self.logger.info("AuthController.authenticate(): cherrypy.request.headers = {}".format(cherrypy.request.headers)) cl = cherrypy.request.headers.get('Content-Length', 0) if cl == 0: # cherrypy.reponse.headers["Status"] = "400" # return 'Bad request' raise cherrypy.HTTPError(status=411) rawbody = cherrypy.request.body.read(int(cl)) self.logger.info("AuthController.authenticate(): rawbody = {}".format(rawbody)) try: credentials = json.loads(rawbody.decode('utf-8')) except Exception as e: self.logger.warning("AuthController.authenticate(): Exception {}".format(e)) return 'Bad, bad request' self.logger.info("AuthController.authenticate(): credentials = {}".format(credentials)) response = {} if self._user_dict == {}: # no password required url = cherrypy.url().split(':')[0] + ':' + cherrypy.url().split(':')[1] payload = {'iss': url, 'iat': self.module.shtime.now(), 'jti': self.module.shtime.now().timestamp()} payload['exp'] = self.module.shtime.now() + timedelta(days=7) payload['ttl'] = 7*24 payload['name'] = 'Autologin' payload['admin'] = True response['token'] = jwt.encode(payload, self.jwt_secret, algorithm='HS256').decode('utf-8') self.logger.info("AuthController.authenticate(): Autologin") self.logger.info("AuthController.authenticate(): payload = {}".format(payload)) else: user = self._user_dict.get(credentials['username'], None) if user: self.logger.info("AuthController.authenticate(): user = {}".format(user)) if Utils.create_hash(user.get('password_hash', 'x')+self.send_hash) == credentials['password']: url = cherrypy.url().split(':')[0] + ':' + cherrypy.url().split(':')[1] payload = {'iss': url, 'iat': self.module.shtime.now(), 'jti': self.module.shtime.now().timestamp()} self.logger.info("AuthController.authenticate() login: login_expiration = {}".format(self.module.login_expiration)) payload['exp'] = self.module.shtime.now() + timedelta(hours=self.module.login_expiration) payload['ttl'] = self.module.login_expiration payload['name'] = user.get('name', '?') payload['admin'] = ('admin' in user.get('groups', [])) response['token'] = jwt.encode(payload, self.jwt_secret, algorithm='HS256').decode('utf-8') self.logger.info("AuthController.authenticate(): payload = {}".format(payload)) self.logger.info("AuthController.authenticate(): response = {}".format(response)) self.logger.info("AuthController.authenticate(): cherrypy.url = {}".format(cherrypy.url())) self.logger.info("AuthController.authenticate(): remote.ip = {}".format(cherrypy.request.remote.ip)) self.logger.info("AuthController.authenticate(): response = {}".format(response)) return json.dumps(response)
def __init__(self, module): self._sh = module._sh self.module = module self.base_dir = self._sh.get_basedir() self.logger = logging.getLogger(__name__) self.etc_dir = self._sh._etc_dir self.modules_dir = os.path.join(self.base_dir, 'modules') #self._user_dict = user_dict self.send_hash = module.send_hash self.jwt_secret = module.jwt_secret http_user_dict = self.module.mod_http.get_user_dict() self._user_dict = {} for user in http_user_dict: if http_user_dict[user]['password_hash'] != '': self._user_dict[Utils.create_hash(user + self.send_hash)] = http_user_dict[user] return
def __init__(self, sh): """ Initialization Routine for the module """ # TO DO: Shortname anders setzen (oder warten bis der Plugin Loader es beim Laden setzt self._shortname = self.__class__.__name__ self._shortname = self._shortname.lower() self.logger = logging.getLogger(__name__) self._sh = sh self.logger.debug("Initializing...") self.logger.debug("Parameters = '{}'".format(str(dict(self._parameters)))) #================================================================================ # Checking and converting parameters # try: self._user = self._parameters['user'] self._password = self._parameters['password'] self._hashed_password = self._parameters['hashed_password'] self._realm = 'shng_http_webif' self._ip = self._parameters['ip'] self._port = self._parameters['port'] self._tls_port = self._parameters['tls_port'] self._use_tls = self._parameters['use_tls'] self._cert_name = self._parameters['tls_cert'] self._privkey_name = self._parameters['tls_key'] self._service_user = self._parameters['service_user'] self._service_password = self._parameters['service_password'] self._service_hashed_password = self._parameters['service_hashed_password'] self._service_realm = 'shng_http_service' self._servicesport = self._parameters['servicesport'] self.threads = self._parameters['threads'] self._showpluginlist = self._parameters['showpluginlist'] self._showservicelist = self._parameters['showservicelist'] self._showtraceback = self._parameters['showtraceback'] self._starturl = self._parameters['starturl'] except: self.logger.critical("Inconsistent module (invalid metadata definition)") self._init_complete = False return self._cert_dir = self._sh._etc_dir self._cert_file = os.path.join(self._cert_dir, self._cert_name) self._privkey_file = os.path.join(self._cert_dir, self._privkey_name) if self._ip == '0.0.0.0': self._ip = self._get_local_ip_address() if self.is_port_in_use(int(self._port)): self.logger.critical("Error starting http module: port {} is already in use".format(self._port)) self._init_complete = False return # test if tls and certificate configuration is correct, otherwise https is not possible if self._use_tls: if self._port == self._tls_port: self.logger.error("'tls_port' can't be the same value as 'port' - https not activated") self._use_tls = False elif not os.path.isfile(self._cert_file): self.logger.error("Certificate '{}' is not installed - https not activated".format(self._cert_name)) self._use_tls = False elif not os.path.isfile(self._privkey_file): self.logger.error("Private key '{}' is not installed - https not activated".format(self._privkey_name)) self._use_tls = False if self._use_tls: if self.is_port_in_use(int(self._tls_port)): self.logger.critical("Error starting http module: TLS-port {} is already in use".format(self._tls_port)) self._init_complete = False return # Check user information and fill _user_dict self._user_dict = {} if self._is_set(self._password) and self._is_set(self._hashed_password): self.logger.warning("http: Webinterfaces: Both 'password' and 'hashed_password' given. Ignoring 'password' and using 'hashed_password'!") self._password = None if self._is_set(self._password) and (not self._is_set(self._hashed_password)): self.logger.warning("http: Webinterfaces: Giving plaintext password in configuration is insecure. Consider using 'hashed_password' instead!") self._hashed_password = Utils.create_hash(self._password) self._password = None self._basic_auth = self._is_set(self._hashed_password) self._user_dict[self._user] = {'password_hash': self._hashed_password, 'name': 'Administrator', 'groups': ['admin']} # Check service-user information and fill _serviceuser_dict self._serviceuser_dict = {} if self._is_set(self._service_password) and self._is_set(self._service_hashed_password): self.logger.warning("http: Services: Both 'service_password' and 'service_hashed_password' given. Ignoring 'service_password' and using 'service_hashed_password'!") self._service_password = None if self._is_set(self._service_password) and (not self._is_set(self._service_hashed_password)): self.logger.warning("http: Services: Giving plaintext service_password in configuration is insecure. Consider using 'service_hashed_password' instead!") self._service_hashed_password = Utils.create_hash(self._service_password) self._service_password = None self._service_basic_auth = self._is_set(self._service_hashed_password) self._serviceuser_dict[self._service_user] = {'password_hash': self._service_hashed_password, 'groups': ['user']} if self._servicesport == 0: self._servicesport = self._port if self._ip == '0.0.0.0': self._ip = self._get_local_ip_address() if self.is_port_in_use(int(self._servicesport)): self.logger.critical("Error starting http module: servicesport {} is already in use".format(self._servicesport)) self._init_complete = False return # ------------------------------------------------------------------------ # Setting up webinterface environment # self.webif_dir = os.path.dirname(os.path.abspath(__file__)) + '/webif' self.gtemplates_dir = self.webif_dir + '/gtemplates' self.gstatic_dir = self.webif_dir + '/gstatic' self.logger.info("Module 'http': ip address = {}, hostname = '{}'".format(self.get_local_ip_address(), self.get_local_hostname())) self.root = ModuleApp(self, self._starturl) if self._use_tls: global_conf = { 'global': { 'engine.autoreload.on': False, 'error_page.404': self._error_page, 'error_page.400': self._error_page, 'error_page.500': self._error_page, 'server.socket_host': self._ip, 'server.socket_port': int(self._tls_port), 'server.ssl_module': 'builtin', # 'server.ssl_module': 'pyOpenSSL', 'server.ssl_certificate': self._cert_file, 'server.ssl_private_key': self._privkey_file, # 'tools.force_tls.on': True, }, } else: global_conf = { 'global': { 'engine.autoreload.on': False, 'error_page.404': self._error_page, 'error_page.400': self._error_page, 'error_page.500': self._error_page, 'server.socket_host': self._ip, 'server.socket_port': int(self._port), }, } # Update the global CherryPy configuration cherrypy.config.update(global_conf) cherrypy.config.update({'log.screen': False}) if self._use_tls: self._server1 = cherrypy._cpserver.Server() self._server1.socket_port=int(self._port) self._server1.socket_host=self._ip self._server1.thread_pool=self.threads self._server1.subscribe() if self._port != self._servicesport: self._server2 = cherrypy._cpserver.Server() self._server2.socket_port=int(self._servicesport) self._server2.socket_host=self._ip self._server2.thread_pool=self.threads self._server2.subscribe() self._build_hostmaps() globaltemplates = self.gtemplates_dir self.tplenv = Environment(loader=FileSystemLoader([os.path.join( self.webif_dir, 'templates' ), globaltemplates] )) self._gstatic_dir = self.webif_dir + '/gstatic' # self.module_conf = { # '/': { # 'tools.staticdir.root': self.webif_dir, # 'tools.staticdir.debug': True, # 'tools.trailing_slash.on': False, # 'log.screen': False, # 'request.dispatch': cherrypy.dispatch.VirtualHost(**self._hostmap), # }, # '/gstatic': { # 'tools.staticdir.on': True, # 'tools.staticdir.dir': 'gstatic', # }, # '/static': { # 'tools.staticdir.on': True, # 'tools.staticdir.dir': 'static', # }, # } self.msg_conf = { '/': { 'tools.staticdir.root': self.webif_dir, }, '/favicon.ico': { 'tools.staticfile.on': True, 'tools.staticfile.filename': self.webif_dir + '/gstatic/img/favicon.ico' }, '/gstatic': { 'tools.staticdir.on': True, 'tools.staticdir.dir': 'gstatic', }, '/static': { 'tools.staticdir.on': True, 'tools.staticdir.dir': 'static' } } # mount the application on the '/' base path (Creating an app-instance on the way) self.root = ModuleApp(self, self._starturl) # self.logger.info("module_conf = {}".format(self.module_conf)) cherrypy.tree.mount(self.root, '/', config = self.msg_conf) # Start the CherryPy HTTP server engine # if self._use_tls: # self.logger.error("PLEASE: Ignore the following cherrypy.error: 'ENGINE Error in HTTPServer.tick' with the exception ending in 'OSError: [Errno 0] Error' (until the CherryPy / Python ssl / openssl v1.1.0 incompatibility is fixed)") cherrypy.engine.start() # Register the plugins-list app and the services-list app self.logger.info("mount '/plugins' - webif_dir = '{}'".format(self.webif_dir)) config = { '/': { 'tools.auth_basic.on': self._basic_auth, 'tools.auth_basic.realm': self._realm, 'tools.auth_basic.checkpassword': self.validate_password, 'tools.staticdir.root': self.webif_dir, }, '/static': { 'tools.staticdir.on': True, 'tools.staticdir.dir': 'static' }, '/gstatic': { 'tools.staticdir.on': True, 'tools.staticdir.dir': 'gstatic', } } config_services = { '/': { 'tools.auth_basic.on': self._service_basic_auth, 'tools.auth_basic.realm': self._service_realm, 'tools.auth_basic.checkpassword': self.validate_service_password, 'tools.staticdir.root': self.webif_dir, }, '/static': { 'tools.staticdir.on': True, 'tools.staticdir.dir': 'static' } } self.logger.info("Module http: config dict: '{}'".format( config ) ) self.logger.info(" - user '{}', password '{}', hashed_password '{}'".format( self._user, self._password, self._hashed_password ) ) if self._showpluginlist == True: # Register the plugin-list as a cherrypy app self.root.plugins = _PluginsApp(self) self.register_webif(self.root.plugins, 'plugins', config) # pluginclass='', instance='', description='', webifname='') if self._showservicelist == True: # Register the service-list as a cherrypy app self.root.services = _ServicesApp(self) self.register_service(self.root.services, 'services', config) # pluginclass='', instance='', description='', servicename='') return