Example #1
0
    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
Example #2
0
 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')
Example #3
0
 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')
Example #4
0
    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)
Example #5
0
    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
Example #6
0
    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