Exemplo n.º 1
0
    def __call__(self, *args, **kwargs):
        if len(kwargs) > 0 and len(args) > 0:
            raise JSONRPCException("JSON-RPC does not support positional and keyword arguments at the same time")

        if not self.__cookieProcessor.has_token():
            # get the cookie
            self.__opener.open(self.__serviceURL).read()

        if len(kwargs):
            postdata = dumps({"method": self.__serviceName, 'params': kwargs, 'id': 'jsonrpc'})
        else:
            postdata = dumps({"method": self.__serviceName, 'params': args, 'id': 'jsonrpc'})

        try:
            if self.__mode == 'POST':
                respdata = self.__opener.open(self.__serviceURL, postdata.encode('utf8')).read()
            else:
                respdata = self.__opener.open(self.__serviceURL + "?" + quote(postdata.encode('utf8'))).read()
        except HTTPError as e:
            error = loads(e.fp.readline())
            raise JSONRPCException(error['error']['message'])

        resp = loads(respdata)
        if resp['error'] != None:
            raise JSONRPCException(resp['error'])

        return resp['result']
Exemplo n.º 2
0
    def process(self, all_props, key, value):

        errors = []

        # Each item of value has to match the given length-rules
        for idx, entry in enumerate(value):
            try:
                loads(entry)
            except Exception as e:
                errors.append(dict(index=idx,
                                   detail=N_("value is no valid JSON string: '%(error)s'"),
                                   error=str(e)))

        return True, errors
Exemplo n.º 3
0
    def commandReceived(self, topic, message):
        """
        Process incoming commands, coming in with session and message
        information.

        ================= ==========================
        Parameter         Description
        ================= ==========================
        message           Received MQTT message
        ================= ==========================

        Incoming messages are coming from an
        :class:`gosa.common.components.mqtt_proxy.MQTTServiceProxy`. The command
        result is written to the '<domain>.client.<client-uuid>' queue.
        """
        err = None
        res = None
        name = None
        args = None
        kwargs = None
        id_ = ''

        response_topic = "%s/response" % "/".join(topic.split("/")[0:4])

        try:
            req = loads(message)
        except Exception as e:
            err = str(e)
            self.log.error("ServiceRequestNotTranslatable: %s" % err)
            req = {'id': topic.split("/")[-2]}

        if err is None:
            try:
                id_ = req['id']
                name = req['method']
                args = req['params']
                kwargs = req['kwparams']

            except KeyError as e:
                self.log.error("KeyError: %s" % e)
                err = str(BadServiceRequest(message))
        self.log.debug("received call [%s] for %s: %s(%s,%s)" % (id_, topic, name, args, kwargs))

        # Try to execute
        if err is None:
            try:
                res = self.__cr.dispatch(name, *args, **kwargs)
            except Exception as e:
                err = str(e)

                # Write exception to log
                exc_type, exc_value, exc_traceback = sys.exc_info()
                self.log.error(traceback.format_exception(exc_type, exc_value, exc_traceback))

        self.log.debug("returning call [%s]: %s / %s" % (id_, res, err))

        response = dumps({"result": res, "id": id_})

        # Get rid of it...
        self.client.send_message(response, topic=response_topic)
Exemplo n.º 4
0
    def handle_message(self, msg):
        message_end = msg[-2:] == b'\n\n'
        for line in msg.strip().splitlines():
            if line == b'ping':
                # skip the ping events
                continue
            (field, value) = line.decode().split(":", 1)
            field = field.strip()
            if field == "data":
                self.last_data += value.strip()
            if field == "id":
                self.last_id = value.strip()
            if field == "event":
                self.last_event = value.strip()
                assert self.last_event == self.check_event

        if message_end:
            data = loads(self.last_data)
            for key in self.check_data:
                assert key in data
                assert data[key] == self.check_data[key]

            self.last_data = ""
            print("msg id %s (%s) received" % (self.last_id, data['uuid']))
            self.stop()
Exemplo n.º 5
0
    def verify(self, user_name, object_dn, key):

        # Do we have read permissions for the requested attribute
        self.__check_acl(user_name, object_dn, "r")

        # Get the object for the given dn
        uuid = self.__dn_to_uuid(object_dn)
        factor_method = self.get_method_from_user(uuid)
        user_settings = self.__settings[
            uuid] if uuid in self.__settings else {}
        if factor_method == "otp":
            totp = TOTP(user_settings.get('otp_secret'))
            return totp.verify(key)

        elif factor_method == "u2f":

            challenge = user_settings.pop('_u2f_challenge_')
            data = loads(key)
            device, c, t = complete_authentication(challenge, data,
                                                   [self.facet])
            return {'keyHandle': device['keyHandle'], 'touch': t, 'counter': c}

        elif factor_method is None:
            return True

        return False
Exemplo n.º 6
0
 def test_getSessionUser(self):
     self.login()
     data = dumps({"id": 1, "method": "getSessionUser", "params": []})
     response = self.fetch('/rpc', method='POST', body=data)
     assert response.code == 200
     json = loads(response.body)
     assert json['result'] == "admin"
Exemplo n.º 7
0
    def parse_event(self, rawEvent):
        """
        Parse the SSE event and call the on_event method with the created event dict
        :param str rawEvent: the raw string retrieved from the SSE server
        """
        event = Event()
        for line in rawEvent.strip().splitlines():
            parts = line.decode().split(":", 1)
            if len(parts) == 2:
                field = parts[0].strip()
                if field == "data":
                    try:
                        data = loads(parts[1].strip())
                    except JSONDecodeError as e:
                        # no json just use string
                        data = parts[1].strip()
                    if event.data is None:
                        event.data = data
                    else:
                        event.data = "%s\n%s" % (event.data, data)
                elif field == "id":
                    event.id = parts[1].strip()
                elif field == "event":
                    event.name = parts[1].strip()

        if event.data is not None:
            self.on_event(event)
Exemplo n.º 8
0
 def process(self, obj, key, valDict):
     if type(valDict[key]['value'] is not None):
         try:
             valDict[key]['value'] = list(map(lambda x: loads(x), valDict[key]['value']))
         except json.decoder.JSONDecodeError as e:
             self.log.error("invalid JSON value property %s [DN=%s]: %s" % (key, obj.dn if obj is not None else '', valDict[key]['value']))
     return key, valDict
Exemplo n.º 9
0
    def configureUserMenu(self, user, user_menu):
        """ configure a users application menu """
        user_menu = loads(user_menu)
        pw_ent = pwd.getpwnam(user)
        uid = pw_ent.pw_uid
        gid = pw_ent.pw_gid

        self.__initialized_dirs = []
        self.home_dir = os.path.expanduser('~%s' % user)
        self.username = user
        self.init_directories(user_menu)
        scripts = self.init_applications(user_menu)
        self.init_menu(user_menu)
        self.chown_dirs(uid, gid)
        if len(scripts) > 0:
            # script files need to be chowned to user always
            for script in scripts:
                self.__chown(script['path'], uid, gid)
                os.chmod(script['path'], stat.S_IRUSR | stat.S_IXUSR)

        for script in scripts:
            # Write gosaApplicationParameter values in execution environment
            environment = {}
            for env_entry in script['environment']:
                environment.update(env_entry)

            script_log = os.path.join(
                self.home_dir, self.local_application_scripts_log,
                os.path.basename(script['path']) + '.log')
            # Run command as user using sudo
            cmd = [
                'sudo', '-n', '-u', user, '"DISPLAY=:0"', '-i', script['path']
            ]
            self.log.debug(
                "executing {script} as {user}, logging to {log}".format(
                    script=" ".join(cmd), user=pw_ent.pw_name, log=script_log))
            try:
                with open(script_log, 'w+') as logfile:
                    p = subprocess.Popen(cmd,
                                         shell=True,
                                         env=environment,
                                         bufsize=-1,
                                         stdout=logfile,
                                         stderr=logfile,
                                         close_fds=True)

                    returncode = p.wait()
                    if returncode != 0:
                        self.log.error(
                            "{} was terminated by signal {}: check {}".format(
                                script['path'], returncode, script_log))
                    else:
                        self.log.info("{} returned {}".format(
                            script['path'], returncode))
            except OSError as e:
                self.log.error("%s execution failed: %s" %
                               (script['path'], str(e)))
            finally:
                if os.path.exists(script_log):
                    self.__chown(script_log, uid, gid)
Exemplo n.º 10
0
    def __call__(self, *args, **kwargs):
        if len(kwargs) > 0 and len(args) > 0:
            raise JSONRPCException("JSON-RPC does not support positional and keyword arguments at the same time")

        # Default to 'core' queue
        call_id = uuid.uuid4()
        topic = "%s/%s" % (self.__serviceAddress, call_id)

        if isinstance(self.__methods, Future):
            self.__methods = yield self.__methods

        if self.__methods and self.__serviceName not in self.__methods:
            raise NameError("name '%s' not defined" % self.__serviceName)

        # Send
        if len(kwargs):
            postdata = dumps({"method": self.__serviceName, 'params': kwargs, 'id': 'jsonrpc'})
        else:
            postdata = dumps({"method": self.__serviceName, 'params': args, 'id': 'jsonrpc'})

        response = yield self.__handler.send_sync_message(postdata, topic)
        resp = loads(response)

        if 'error' in resp and resp['error'] is not None:
            raise JSONRPCException(resp['error'])

        raise gen.Return(response)
Exemplo n.º 11
0
    def process(self, topic, message):

        try:
            req = loads(message)
        except ValueError as e:
            raise ValueError(C.make_error("INVALID_JSON", data=str(e)))

        try:
            id_ = req['id']
            name = req['method']
            args = req['params']
            kwargs = req['kwparams']
            if 'user' in req:
                user = req['user']
            else:
                user = topic.split("/")[2]
            sid = req['session_id'] if 'session_id' in req else None

        except KeyError as e:
            self.log.error("KeyError: %s" % e)
            raise BadServiceRequest(message)

        self.log.debug("received call [%s, user=%s, session-id=%s] for %s: %s(%s,%s)" % (id_, user, sid, topic, name, args, kwargs))

        try:
            return id_, self.__command_registry.dispatch(user, sid, name, *args, **kwargs)
        except Exception as e:
            # Write exception to log
            exc_type, exc_value, exc_traceback = sys.exc_info()
            self.log.error("".join(traceback.format_exception(exc_type, exc_value, exc_traceback)))
            raise e
Exemplo n.º 12
0
    def setPasswordRecoveryAnswers(self, user, object_dn, data):
        """
        Set the password recovery answers for a user
        """
        data = loads(data)

        # Do we have read permissions for the requested attribute
        env = Environment.getInstance()
        topic = "%s.objects.%s.attributes.%s" % (env.domain, "User", "passwordRecoveryHash")
        aclresolver = PluginRegistry.getInstance("ACLResolver")
        if not aclresolver.check(user, topic, "w", base=object_dn):

            self.__log.debug("user '%s' has insufficient permissions to write %s on %s, required is %s:%s" % (
                user, "isLocked", object_dn, topic, "w"))
            raise ACLException(C.make_error('PERMISSION_ACCESS', topic, target=object_dn))

        user = ObjectProxy(object_dn)
        method = user.passwordMethod

        # Try to detect the responsible password method-class
        pwd_o = self.get_method_by_method_type(method)
        if not pwd_o:
            raise PasswordException(C.make_error("PASSWORD_UNKNOWN_HASH", type=method))

        # hash the new answers
        for idx, answer in data.items():
            data[idx] = pwd_o.generate_password_hash(self.clean_string(answer), method)
            print("%s encrypted with %s as index %s => %s" % (self.clean_string(answer), method, idx, data[idx]))

        # Set the password and commit the changes
        user.passwordRecoveryHash = dumps(data)
        user.commit()
Exemplo n.º 13
0
Arquivo: main.py Projeto: gonicus/gosa
    def verify(self, user_name, object_dn, key):

        # Do we have read permissions for the requested attribute
        self.__check_acl(user_name, object_dn, "r")

        # Get the object for the given dn
        uuid = self.__dn_to_uuid(object_dn)
        factor_method = self.get_method_from_user(uuid)
        user_settings = self.__settings[uuid] if uuid in self.__settings else {}
        if factor_method == "otp":
            totp = TOTP(user_settings.get('otp_secret'))
            return totp.verify(key)

        elif factor_method == "u2f":

            challenge = user_settings.pop('_u2f_challenge_')
            data = loads(key)
            device, c, t = complete_authentication(challenge, data, [self.facet])
            return {
                'keyHandle': device['keyHandle'],
                'touch': t,
                'counter': c
            }

        elif factor_method is None:
            return True

        return False
Exemplo n.º 14
0
Arquivo: main.py Projeto: peuter/gosa
    def verify(self, user_name, object_dn, key):

        # Do we have read permissions for the requested attribute
        self.__check_acl(user_name, object_dn, "r")

        # Get the object for the given dn
        user = ObjectProxy(object_dn)
        factor_method = self.get_method_from_user(user)
        user_settings = self.__settings[
            user.uuid] if user.uuid in self.__settings else {}
        if factor_method == "otp":
            totp = TOTP(user_settings.get('otp_secret'))
            return totp.verify(key)

        elif factor_method == "u2f":
            devices = [
                DeviceRegistration.wrap(device)
                for device in user_settings.get('_u2f_devices_', [])
            ]

            challenge = user_settings.pop('_u2f_challenge_')
            data = loads(key)
            c, t = verify_authenticate(devices, challenge, data, [self.facet])
            return {'touch': t, 'counter': c}

        elif factor_method is None:
            return True

        return False
Exemplo n.º 15
0
Arquivo: main.py Projeto: peuter/gosa
    def verify(self, user_name, object_dn, key):

        # Do we have read permissions for the requested attribute
        self.__check_acl(user_name, object_dn, "r")

        # Get the object for the given dn
        user = ObjectProxy(object_dn)
        factor_method = self.get_method_from_user(user)
        user_settings = self.__settings[user.uuid] if user.uuid in self.__settings else {}
        if factor_method == "otp":
            totp = TOTP(user_settings.get('otp_secret'))
            return totp.verify(key)

        elif factor_method == "u2f":
            devices = [DeviceRegistration.wrap(device)
                       for device in user_settings.get('_u2f_devices_', [])]

            challenge = user_settings.pop('_u2f_challenge_')
            data = loads(key)
            c, t = verify_authenticate(devices, challenge, data, [self.facet])
            return {
                'touch': t,
                'counter': c
            }

        elif factor_method is None:
            return True

        return False
Exemplo n.º 16
0
    def process(self, topic, message):

        try:
            req = loads(message)
        except ValueError as e:
            raise ValueError(C.make_error("INVALID_JSON", data=str(e)))

        try:
            id_ = req['id']
            name = req['method']
            args = req['params']
            user = req['user'] if 'user' in req else topic.split("/")[2]
            sid = req['session_id'] if 'session_id' in req else None

        except KeyError as e:
            self.log.error("KeyError: %s" % e)
            raise BadServiceRequest(message)

        self.log.debug("received call [%s] for %s: %s(%s)" %
                       (id_, topic, name, args))

        try:
            return id_, self.__command_registry.dispatch(
                user, sid, name, *args)
        except Exception as e:
            # Write exception to log
            exc_type, exc_value, exc_traceback = sys.exc_info()
            self.log.error("".join(
                traceback.format_exception(exc_type, exc_value,
                                           exc_traceback)))
            raise e
Exemplo n.º 17
0
    def handle_message(self, msg):
        message_end = msg[-2:] == b'\n\n'
        for line in msg.strip().splitlines():
            if line == b'ping':
                # skip the ping events
                continue
            (field, value) = line.decode().split(":", 1)
            field = field.strip()
            if field == "data":
                self.last_data += value.strip()
            if field == "id":
                self.last_id = value.strip()
            if field == "event":
                self.last_event = value.strip()
                assert self.last_event == self.check_event

        if message_end:
            data = loads(self.last_data)
            for key in self.check_data:
                assert key in data
                assert data[key] == self.check_data[key]

            self.last_data = ""
            print("msg id %s (%s) received" % (self.last_id, data['uuid']))
            self.stop()
Exemplo n.º 18
0
    def __init__(self):
        self.env = Environment.getInstance()
        settings_file = self.env.config.get("webhooks.registry-store", "/var/lib/gosa/webhooks")
        if not os.path.exists(os.path.dirname(settings_file)):
            os.makedirs(os.path.dirname(settings_file))

        if os.path.exists(settings_file):
            with open(settings_file, 'r') as f:
                self.__hooks = loads(f.read())
Exemplo n.º 19
0
    def test_unknown(self):
        self.login()
        data = dumps({"id": 1, "method": "unknownmethod", "params": []})
        response = self.fetch('/rpc', method='POST', body=data)

        assert response.code == 500
        json = loads(response.body)
        assert json['error']['code'] == 100
        assert json['error']['name'] == "JSONRPCError"
Exemplo n.º 20
0
Arquivo: main.py Projeto: peuter/gosa
 def getDashboardWidgets(self):
     plugins = []
     for root, dirs, files in os.walk(os.path.join(frontend_path, 'gosa', 'uploads', 'widgets')):
         for d in dirs:
             manifest_path = os.path.join(root, d, "Manifest.json")
             if os.path.exists(manifest_path):
                 with open(manifest_path) as f:
                     plugin_data = loads(f.read())
                     plugins.append(plugin_data)
     return plugins
Exemplo n.º 21
0
    def test_login(self):
        # successful login
        with unittest.mock.patch.object(JsonRpcHandler, 'authenticate', return_value='cn=System Administrator,ou=people,dc=example,'
                                                                                     'dc=net') as m:
            response = self.login()
            assert response.code == 200
            json = loads(response.body)
            assert json['result']['state'] == AUTH_SUCCESS
            assert json['error'] is None
            assert json['id'] == 0

        # failed login
        with unittest.mock.patch.object(JsonRpcHandler, 'authenticate', return_value=False) as m:
            response = self.login()
            json = loads(response.body)
            assert json['result']['state'] == AUTH_LOCKED

            # reset lock
            JsonRpcHandler._JsonRpcHandler__dos_manager = {}
Exemplo n.º 22
0
Arquivo: main.py Projeto: gonicus/gosa
 def __load_widgets(self, path):
     widgets = []
     for root, dirs, files in os.walk(path):
         for d in dirs:
             manifest_path = os.path.join(root, d, "Manifest.json")
             if os.path.exists(manifest_path):
                 with open(manifest_path) as f:
                     plugin_data = loads(f.read())
                     widgets.append(plugin_data)
     return widgets
Exemplo n.º 23
0
Arquivo: main.py Projeto: GOsa3/gosa
    def getDashboardWidgets(self):
        plugins = []
#TODO: wrong path, needs to be configurable
        for root, dirs, files in os.walk(os.path.join(frontend_path, 'gosa', 'uploads', 'widgets')):
            for d in dirs:
                manifest_path = os.path.join(root, d, "Manifest.json")
                if os.path.exists(manifest_path):
                    with open(manifest_path) as f:
                        plugin_data = loads(f.read())
                        plugins.append(plugin_data)
        return plugins
Exemplo n.º 24
0
Arquivo: main.py Projeto: gonicus/gosa
    def configureUserMenu(self, user, user_menu):
        """ configure a users application menu """
        user_menu = loads(user_menu)
        pw_ent = pwd.getpwnam(user)
        uid = pw_ent.pw_uid
        gid = pw_ent.pw_gid

        self.__initialized_dirs = []
        self.home_dir = os.path.expanduser('~%s' % user)
        self.username = user
        self.init_directories(user_menu)
        scripts = self.init_applications(user_menu)
        self.init_menu(user_menu)
        self.chown_dirs(uid, gid)
        if len(scripts) > 0:
            # script files need to be chowned to user always
            for script in scripts:
                self.__chown(script['path'], uid, gid)
                os.chmod(script['path'], stat.S_IRUSR | stat.S_IXUSR)

        for script in scripts:
            # Write gosaApplicationParameter values in execution environment
            environment = {}
            for env_entry in script['environment']:
               environment.update(env_entry)

            script_log = os.path.join(self.home_dir, self.local_application_scripts_log, os.path.basename(script['path']) + '.log')
            # Run command as user using sudo
            cmd = ['sudo', '-n', '-u', user, 'DISPLAY={DISPLAY}'.format(DISPLAY=self.getDisplay()), '-i', script['path']]
            self.log.debug("executing {script} as {user}, logging to {log}".format(script=" ".join(cmd), user=pw_ent.pw_name, log=script_log))
            try:
                with open(script_log, 'w+') as logfile:
                    p = subprocess.Popen(
                        cmd,
                        shell=False,
                        env=environment,
                        bufsize=-1,
                        stdout=logfile,
                        stderr=logfile,
                        close_fds=True
                    )

                    returncode = p.wait()
                    if returncode != 0:
                        self.log.error("{} was terminated by signal {}: check {}".format(script['path'], returncode, script_log))
                    else:
                        self.log.info("{} returned {}".format(script['path'], returncode))
            except OSError as e:
                self.log.error("%s execution failed: %s" % (script['path'], str(e)))
            finally:
                if os.path.exists(script_log):
                    self.__chown(script_log, uid, gid)
Exemplo n.º 25
0
 def test_exception(self):
     self.login()
     data = dumps({
         "id": 1,
         "method": "getSessionUser",
         "params": {
             'test': 'test'
         }
     })
     response = self.fetch('/rpc', method='POST', body=data)
     assert response.code == 500
     json = loads(response.body)
     assert json['error']['code'] == 100
     assert json['error']['name'] == "JSONRPCError"
Exemplo n.º 26
0
 def test_getSessionUser(self):
     self.login()
     data = dumps({
         "id": 1,
         "method": "getSessionUser",
         "params": []
     })
     response = self.fetch('/rpc',
                           method='POST',
                           body=data
                           )
     assert response.code == 200
     json = loads(response.body)
     assert json['result'] == "admin"
Exemplo n.º 27
0
 def test_exception(self):
     self.login()
     data = dumps({
         "id": 1,
         "method": "getSessionUser",
         "params": {'test': 'test'}
     })
     response = self.fetch('/rpc',
                           method='POST',
                           body=data
                           )
     assert response.code == 500
     json = loads(response.body)
     assert json['error']['code'] == 500
     assert json['error']['name'] == "JSONRPCError"
Exemplo n.º 28
0
    def test_login(self):
        # successful login
        with unittest.mock.patch.object(
                JsonRpcHandler,
                'authenticate',
                return_value='cn=System Administrator,ou=people,dc=example,'
                'dc=net') as m:
            response = self.login()
            assert response.code == 200
            json = loads(response.body)
            assert json['result']['state'] == AUTH_SUCCESS
            assert json['error'] is None
            assert json['id'] == 0

        # failed login
        with unittest.mock.patch.object(JsonRpcHandler,
                                        'authenticate',
                                        return_value=False) as m:
            response = self.login()
            json = loads(response.body)
            assert json['result']['state'] == AUTH_LOCKED

            # reset lock
            JsonRpcHandler._JsonRpcHandler__dos_manager = {}
Exemplo n.º 29
0
    def test_unknown(self):
        self.login()
        data = dumps({
            "id": 1,
            "method": "unknownmethod",
            "params": []
        })
        response = self.fetch('/rpc',
                              method='POST',
                              body=data
                              )

        assert response.code == 500
        json = loads(response.body)
        assert json['error']['code'] == 100
        assert json['error']['name'] == "JSONRPCError"
Exemplo n.º 30
0
    def __on_message(self, client, userdata, message):
        payload = loads(message.payload)
        if self.__sender_id is not None and payload['sender_id'] == self.__sender_id:
            # skip own messages
            return

        subs = self.get_subscriptions(message.topic)
        for sub in subs:
            if sub['sync'] is True:
                self.log.debug("incoming message for synced topic %s" % message.topic)
                self.__sync_message_queues[message.topic].put(payload['content'])
            if 'callback' in sub and sub['callback'] is not None:
                callback = sub['callback']
                callback(message.topic, payload['content'])
        if len(subs) == 0:
            self.log.warning("Incoming message for unhandled topic '%s'" % message.topic)
Exemplo n.º 31
0
    def serve(self):
        # load hooks
        settings_file = self.env.config.get("webhooks.registry-store", "/var/lib/gosa/webhooks")
        if os.path.exists(settings_file):
            with open(settings_file, 'r') as f:
                self.__hooks = loads(f.read())

        # load registered handlers
        for entry in pkg_resources.iter_entry_points("gosa.webhook_handler"):
            module = entry.load()
            self.__handlers[entry.name] = module()

        # override for development mode
        monitor_key = self.env.config.get("webhooks.ldap_monitor_token")
        if monitor_key:
            if 'application/vnd.gosa.event+xml' not in self.__hooks:
                self.__hooks['application/vnd.gosa.event+xml'] = {}
            self.__hooks['application/vnd.gosa.event+xml']['backend-monitor'] = monitor_key
Exemplo n.º 32
0
    def __call__(self, *args, **kwargs):
        data = {}
        if '__user__' in kwargs:
            data['user'] = kwargs['__user__']
            del kwargs['__user__']
        if '__session_id__' in kwargs:
            data['session_id'] = kwargs['__session_id__']
            del kwargs['__session_id__']

        if len(kwargs) > 0 and len(args) > 0:
            raise JSONRPCException(
                "JSON-RPC does not support positional and keyword arguments at the same time"
            )

        # Default to 'core' queue
        call_id = uuid.uuid4()
        topic = "%s/%s" % (self.__serviceAddress, call_id)

        if isinstance(self.__methods, Future):
            self.__methods = yield self.__methods

        if self.__methods and self.__serviceName not in self.__methods:
            raise NameError("name '%s' not defined" % self.__serviceName)

        # Send
        data.update({
            "method": self.__serviceName,
            "id": "jsonrpc",
            "sender": self.env.uuid
        })
        if len(kwargs):
            data["params"] = kwargs
        else:
            data["params"] = args
        postdata = dumps(data)

        response = yield self.__handler.send_sync_message(postdata, topic)
        resp = loads(response)

        if 'error' in resp and resp['error'] is not None:
            raise JSONRPCException(resp['error'])

        return resp['result']
Exemplo n.º 33
0
    def serve(self):
        # load hooks
        settings_file = self.env.config.get("webhooks.registry-store",
                                            "/var/lib/gosa/webhooks")
        if os.path.exists(settings_file):
            with open(settings_file, 'r') as f:
                self.__hooks = loads(f.read())

        # load registered handlers
        for entry in pkg_resources.iter_entry_points("gosa.webhook_handler"):
            module = entry.load()
            self.__handlers[entry.name] = module()

        # override for development mode
        monitor_key = self.env.config.get("webhooks.ldap_monitor_token")
        if monitor_key:
            if 'application/vnd.gosa.event+xml' not in self.__hooks:
                self.__hooks['application/vnd.gosa.event+xml'] = {}
            self.__hooks['application/vnd.gosa.event+xml'][
                'backend-monitor'] = monitor_key
Exemplo n.º 34
0
Arquivo: main.py Projeto: peuter/gosa
    def completeU2FRegistration(self, user_name, object_dn, data):

        # Do we have write permissions for the requested attribute
        self.__check_acl(user_name, object_dn, "w")

        user = ObjectProxy(object_dn)
        user_settings = self.__settings[user.uuid]
        data = loads(data)
        binding, cert = complete_register(user_settings.pop('_u2f_enroll_'), data,
                                          [self.facet])
        devices = [DeviceRegistration.wrap(device)
                   for device in user_settings.get('_u2f_devices_', [])]
        devices.append(binding)
        user_settings['_u2f_devices_'] = [d.json for d in devices]
        self.__save_settings()

        self.__log.info("U2F device enrolled. Username: %s", user_name)
        self.__log.debug("Attestation certificate:\n%s", cert.public_bytes(Encoding.PEM))

        return True
Exemplo n.º 35
0
    def __on_message(self, client, userdata, message):
        payload = loads(message.payload)
        if self.__sender_id is not None and payload[
                'sender_id'] == self.__sender_id:
            # skip own messages
            return

        subs = self.get_subscriptions(message.topic)
        for sub in subs:
            if sub['sync'] is True:
                self.log.debug("incoming message for synced topic %s" %
                               message.topic)
                self.__sync_message_queues[message.topic].put(
                    payload['content'])
            if 'callback' in sub and sub['callback'] is not None:
                callback = sub['callback']
                callback(message.topic, payload['content'])
        if len(subs) == 0:
            self.log.warning("Incoming message for unhandled topic '%s'" %
                             message.topic)
Exemplo n.º 36
0
    def test_logout(self):
        # fetch the xsrf cookie
        self.fetch('/rpc', method='GET')
        data = dumps({"id": 3, "method": "logout", "params": []})
        response = self.fetch('/rpc', method='POST', body=data)
        # logging out before beeing logged in is not allowed
        assert response.code == 401

        self.login()
        response = self.fetch('/rpc', method='POST', body=data)

        assert response.code == 200
        json = loads(response.body)
        assert json['result'] is True
        assert json['error'] is None
        assert json['id'] == 3

        # check if we are logged out
        data = dumps({"id": 3, "method": "getSessionUser", "params": []})
        response = self.fetch('/rpc', method='POST', body=data)
        assert response.code == 401
Exemplo n.º 37
0
Arquivo: main.py Projeto: GOsa3/gosa
    def handle_request(self, request_handler):
        foreman = PluginRegistry.getInstance("Foreman")
        self.log.debug(request_handler.request.body)
        data = loads(request_handler.request.body)

        if data["action"] in ForemanRealmReceiver.skip_next_event:
            del ForemanRealmReceiver.skip_next_event[data["action"]]
            return

        # TODO disable hook logging to file
        with open("foreman-log.json", "a") as f:
            f.write("%s,\n" % dumps(data, indent=4, sort_keys=True))

        ForemanBackend.modifier = "foreman"
        if data['action'] == "create":
            # new client -> join it
            try:
                key = yield foreman.add_host(data['hostname'])

                # send key as otp to foremans realm proxy
                request_handler.finish(dumps({
                    "randompassword": key
                }))
            except Exception as e:
                request_handler.finish(dumps({
                    "error": "%s" % e
                }))
                raise e

        elif data['action'] == "delete":
            try:
                foreman.remove_type("ForemanHost", data['hostname'])
            except Exception as e:
                request_handler.finish(dumps({
                    "error": "%s" % e
                }))
                raise e

        ForemanBackend.modifier = None
Exemplo n.º 38
0
    def __handle_result(self, response):
        """
        Handle the results of the different login steps (login, 2FA, U2F) and process with
        the next required step until the login process succeeds or fails.
        """
        try:
            result_code = int(response['state'])

            if result_code == AUTH_FAILED:
                print(_("Login of user '%s' failed") % self.__username)
                sys.exit(1)

            elif result_code == AUTH_OTP_REQUIRED:
                key = input(_("OTP-Passkey: "))
                return self.__handle_result(self.proxy.verify(key))

            elif result_code == AUTH_U2F_REQUIRED and 'u2f_data' in response:
                for device in u2f.list_devices():
                    with device as dev:
                        data = loads(response['u2f_data'])
                        print(data)
                        print(_("Please touch the flashing U2F device now."))
                        for request in data['authenticateRequests']:
                            data = u2f.authenticate(device, request,
                                                    request['appId'])
                            res = self.proxy.verify(data)
                            if 'counter' in res and 'touch' in res:
                                return True

                return False
            elif result_code == AUTH_SUCCESS:
                return True

        except Exception as e:
            print(e)
            sys.exit(1)

        return False
Exemplo n.º 39
0
    def __handle_result(self, response):
        """
        Handle the results of the different login steps (login, 2FA, U2F) and process with
        the next required step until the login process succeeds or fails.
        """
        try:
            print(response)
            result_code = int(response['state'])

            if result_code == AUTH_FAILED:
                print(_("Login of user '%s' failed") % self.__username)
                sys.exit(1)

            elif result_code == AUTH_OTP_REQUIRED:
                key = input(_("OTP-Passkey: "))
                return self.__handle_result(self.proxy.verify(key))

            elif result_code == AUTH_U2F_REQUIRED and 'u2f_data' in response:
                for device in u2f.list_devices():
                    with device as dev:
                        data = loads(response['u2f_data'])
                        print(data)
                        print(_("Please touch the flashing U2F device now."))
                        for request in data['authenticateRequests']:
                            data = u2f.authenticate(device, request, request['appId'])
                            res = self.proxy.verify(data)
                            if 'counter' in res and 'touch' in res:
                                return True

                return False
            elif result_code == AUTH_SUCCESS:
                return True

        except Exception as e:
            print(e)
            sys.exit(1)

        return False
Exemplo n.º 40
0
    def setPasswordRecoveryAnswers(self, user, object_dn, data):
        """
        Set the password recovery answers for a user
        """
        data = loads(data)

        # Do we have read permissions for the requested attribute
        env = Environment.getInstance()
        topic = "%s.objects.%s.attributes.%s" % (env.domain, "User",
                                                 "passwordRecoveryHash")
        aclresolver = PluginRegistry.getInstance("ACLResolver")
        if not aclresolver.check(user, topic, "w", base=object_dn):

            self.__log.debug(
                "user '%s' has insufficient permissions to write %s on %s, required is %s:%s"
                % (user, "isLocked", object_dn, topic, "w"))
            raise ACLException(
                C.make_error('PERMISSION_ACCESS', topic, target=object_dn))

        user = ObjectProxy(object_dn)
        method = user.passwordMethod

        # Try to detect the responsible password method-class
        pwd_o = self.get_method_by_method_type(method)
        if not pwd_o:
            raise PasswordException(
                C.make_error("PASSWORD_UNKNOWN_HASH", type=method))

        # hash the new answers
        for idx, answer in data.items():
            data[idx] = pwd_o.generate_password_hash(self.clean_string(answer),
                                                     method)
            print("%s encrypted with %s as index %s => %s" %
                  (self.clean_string(answer), method, idx, data[idx]))

        # Set the password and commit the changes
        user.passwordRecoveryHash = dumps(data)
        user.commit()
Exemplo n.º 41
0
    def test_logout(self):
        # fetch the xsrf cookie
        self.fetch('/rpc', method='GET')
        data = dumps({
            "id": 3,
            "method": "logout",
            "params": []
        })
        response = self.fetch('/rpc',
                          method='POST',
                          body=data
                          )
        # logging out before beeing logged in is not allowed
        assert response.code == 401

        self.login()
        response = self.fetch('/rpc',
                              method='POST',
                              body=data
                              )

        assert response.code == 200
        json = loads(response.body)
        assert json['result'] is True
        assert json['error'] is None
        assert json['id'] == 3

        # check if we are logged out
        data = dumps({
            "id": 3,
            "method": "getSessionUser",
            "params": []
        })
        response = self.fetch('/rpc',
                              method='POST',
                              body=data
                              )
        assert response.code == 401
Exemplo n.º 42
0
    def __on_message(self, client, userdata, message):
        self.log.debug("%s: __on_message client='%s', userdata='%s', message='%s'" % (self.get_identifier(), client, userdata, message.payload))
        payload = loads(message.payload)
        if isinstance(payload, dict) and "content" in payload:
            content = payload["content"]
            if self.__sender_id is not None and 'sender_id' in payload and payload['sender_id'] == self.__sender_id:
                # skip own messages
                return
        else:
            content = payload

        subs = self.get_subscriptions(message.topic)
        for sub in subs:
            if sub['sync'] is True:
                self.log.debug("%s: incoming message for synced topic %s" % (self.get_identifier(), message.topic))
                self.__sync_message_queues[message.topic].put(content)
            if 'callback' in sub and sub['callback'] is not None:
                callback = sub['callback']
                callback(message.topic, content)
            elif sub['sync'] is not True:
                self.log.warning("Incoming message not processed by async subscription because of missing callback")
        if len(subs) == 0:
            self.log.warning("Incoming message for unhandled topic '%s'" % message.topic)
Exemplo n.º 43
0
Arquivo: main.py Projeto: peuter/gosa
    def completeU2FRegistration(self, user_name, object_dn, data):

        # Do we have write permissions for the requested attribute
        self.__check_acl(user_name, object_dn, "w")

        user = ObjectProxy(object_dn)
        user_settings = self.__settings[user.uuid]
        data = loads(data)
        binding, cert = complete_register(user_settings.pop('_u2f_enroll_'),
                                          data, [self.facet])
        devices = [
            DeviceRegistration.wrap(device)
            for device in user_settings.get('_u2f_devices_', [])
        ]
        devices.append(binding)
        user_settings['_u2f_devices_'] = [d.json for d in devices]
        self.__save_settings()

        self.__log.info("U2F device enrolled. Username: %s", user_name)
        self.__log.debug("Attestation certificate:\n%s",
                         cert.public_bytes(Encoding.PEM))

        return True
Exemplo n.º 44
0
    def __call__(self, *args, **kwargs):
        if len(kwargs) > 0 and len(args) > 0:
            raise JSONRPCException(
                "JSON-RPC does not support positional and keyword arguments at the same time"
            )

        # Default to 'core' queue
        call_id = uuid.uuid4()
        topic = "%s/%s" % (self.__serviceAddress, call_id)

        if isinstance(self.__methods, Future):
            self.__methods = yield self.__methods

        if self.__methods and self.__serviceName not in self.__methods:
            raise NameError("name '%s' not defined" % self.__serviceName)

        # Send
        if len(kwargs):
            postdata = dumps({
                "method": self.__serviceName,
                'params': kwargs,
                'id': 'jsonrpc'
            })
        else:
            postdata = dumps({
                "method": self.__serviceName,
                'params': args,
                'id': 'jsonrpc'
            })

        response = yield self.__handler.send_sync_message(postdata, topic)
        resp = loads(response)

        if 'error' in resp and resp['error'] is not None:
            raise JSONRPCException(resp['error'])

        raise gen.Return(response)
Exemplo n.º 45
0
    def __call__(self, *args, **kwargs):
        data = {}
        if '__user__' in kwargs:
            data['user'] = kwargs['__user__']
            del kwargs['__user__']
        if '__session_id__' in kwargs:
            data['session_id'] = kwargs['__session_id__']
            del kwargs['__session_id__']

        # Default to 'core' queue
        call_id = uuid.uuid4()
        topic = "%s/%s" % (self.__serviceAddress, call_id)

        if isinstance(self.__methods, Future):
            self.__methods = yield self.__methods

        if self.__methods and self.__serviceName not in self.__methods:
            raise NameError("name '%s' not defined" % self.__serviceName)

        # Send
        data.update({
            "method": self.__serviceName,
            "id": "mqttrpc",
            "sender": self.env.uuid
        })
        data["kwparams"] = kwargs
        data["params"] = args
        postdata = dumps(data)

        response = yield self.__handler.send_sync_message(postdata, topic, qos=2)
        resp = loads(response)

        if 'error' in resp and resp['error'] is not None:
            raise JSONRPCException(resp['error'])

        return resp['result']
Exemplo n.º 46
0
 def parse_event(self, rawEvent):
     """
     Parse the SSE event and call the on_event method with the created event dict
     :param str rawEvent: the raw string retrieved from the SSE server
     """
     event = Event()
     for line in rawEvent.strip().splitlines():
         (field, value) = line.decode().split(":", 1)
         field = field.strip()
         if field == "data":
             try:
                 data = loads(value.strip())
             except JSONDecodeError as e:
                 # no json just use string
                 data = value.strip()
             if event.data is None:
                 event.data = data
             else:
                 event.data = "%s\n%s" % (event.data, data)
         elif field == "id":
             event.id = value.strip()
         elif field == "event":
             event.name = value.strip()
     self.on_event(event)
Exemplo n.º 47
0
Arquivo: main.py Projeto: peuter/gosa
 def __reload(self):
     if not os.path.exists(self.settings_file):
         self.__save_settings()
     else:
         with open(self.settings_file, "r") as f:
             self.__settings = loads(f.read())
Exemplo n.º 48
0
    def requestPasswordReset(self, uid, step, uuid=None, data=None):
        """
        Request a password reset if the submitted password recovery answers match the stored ones for the given user
        :param uid: user id
        :param step: 'start' to trigger the password reset process by sending an email with activation link to the user
        :param uuid: the recovery uuid
        :param data: optional data required by the current step
        :return: *
        """

        # check for existing uid and status of the users password settings
        index = PluginRegistry.getInstance("ObjectIndex")
        res = index.search({'uid': uid, '_type': 'User'}, {'dn': 1})
        if len(res) == 0:
            raise PasswordException(C.make_error("UID_UNKNOWN", target=uid))
        dn = res[0]['dn']
        user = ObjectProxy(dn)
        if user.mail is None:
            raise PasswordException(
                C.make_error("PASSWORD_RECOVERY_IMPOSSIBLE"))

        recovery_state = loads(
            user.passwordRecoveryState
        ) if user.passwordRecoveryState is not None else {}

        if step != "start":
            # check uuid
            if 'uuid' not in recovery_state or recovery_state['uuid'] != uuid:
                # recovery process has not been started
                raise PasswordException(
                    C.make_error("PASSWORD_RECOVERY_STATE_ERROR"))

        if step == "start":
            # start process by generating an unique password recovery link for this user and sending it to him via mail

            if 'uuid' not in recovery_state:
                # generate a new id
                recovery_state['sent_counter'] = 0
                recovery_state['uuid'] = str(Uuid.uuid4())
                recovery_state['state'] = 'started'

            # send the link to the user
            content = N_(
                "Please open this link to continue your password recovery process."
            ) + ":"
            gui = PluginRegistry.getInstance("HTTPService").get_gui_uri()
            content += "\n\n%s?pwruid=%s&uid=%s\n\n" % (
                "/".join(gui), recovery_state['uuid'], uid)

            mail = PluginRegistry.getInstance("Mail")
            mail.send(user.mail, N_("Password recovery link"), content)
            recovery_state["sent_counter"] += 1

            user.passwordRecoveryState = dumps(recovery_state)
            user.commit()
            return True

        elif step == "get_questions":
            # check correct state
            if recovery_state['state'] is None:
                raise PasswordException(
                    C.make_error("PASSWORD_RECOVERY_STATE_ERROR"))

            # return the indices of the questions the user has answered
            recovery_hashes = loads(user.passwordRecoveryHash)
            # TODO retrieve minimum amount of correct answers from user policy object
            return random.sample(recovery_hashes.keys(), 3)

        elif step == "check_answers":
            # check correct state
            if recovery_state['state'] is None:
                raise PasswordException(
                    C.make_error("PASSWORD_RECOVERY_STATE_ERROR"))

            data = loads(data)
            recovery_hashes = loads(user.passwordRecoveryHash)
            correct_answers = 0
            for idx, answer in data.items():
                if idx not in recovery_hashes:
                    # the user hasn't answered this question
                    continue
                # detect method from existing answer
                pwd_o = self.detect_method_by_hash(recovery_hashes[idx])
                if not pwd_o:
                    raise PasswordException(
                        C.make_error("PASSWORD_RECOVERY_IMPOSSIBLE"))

                # encrypt and compare new answer
                if pwd_o.compare_hash(self.clean_string(answer),
                                      recovery_hashes[idx]):
                    correct_answers += 1

            # TODO retrieve minimum amount of correct answers from user policy object
            if correct_answers >= 3:
                recovery_state['state'] = 'verified'
                user.passwordRecoveryState = dumps(recovery_state)
                user.commit()
                return True
            else:
                return False

        elif step == "change_password":
            # check correct state
            if recovery_state['state'] != 'verified':
                raise PasswordException(
                    C.make_error("PASSWORD_RECOVERY_STATE_ERROR"))

            self.setUserPassword(uid, user.dn, data)

            user.passwordRecoveryState = None
            user.commit()
            return True
Exemplo n.º 49
0
 def __init__(self):
     self.env = Environment.getInstance()
     settings_file = self.env.config.get("webhooks.registry-store", "/var/lib/gosa/webhooks")
     if os.path.exists(settings_file):
         with open(settings_file, 'r') as f:
             self.__hooks = loads(f.read())
Exemplo n.º 50
0
Arquivo: main.py Projeto: gonicus/gosa
    def writePPD(self, printer_cn, server_ppd_file, custom_ppd_file, data):
        if self.client is None:
            return

        server_ppd = None
        dir = self.env.config.get("cups.spool", default="/tmp/spool")
        if not os.path.exists(dir):
            os.makedirs(dir)
        try:
            server_ppd = self.client.getServerPPD(server_ppd_file)
            is_server_ppd = True
            ppd = cups.PPD(server_ppd)
        except Exception as e:
            self.log.error(str(e))
            is_server_ppd = False

            if custom_ppd_file is not None:
                ppd = cups.PPD(os.path.join(dir, custom_ppd_file))
            else:
                raise PPDException(C.make_error('COULD_NOT_READ_SOURCE_PPD'))

        if isinstance(data, str):
            data = loads(data)

        # apply options
        for option_name, value in data.items():
            option = ppd.findOption(option_name)
            if option is not None:
                conflicts = ppd.markOption(option_name, value)
                if conflicts > 0:
                    raise PPDException(C.make_error('OPTION_CONFLICT', option=option_name, value=value, conflicts=conflicts))
            else:
                raise PPDException(C.make_error('OPTION_NOT_FOUND', option=option_name))

        # calculate hash value for new PPD

        temp_file = tempfile.NamedTemporaryFile(delete=False)
        try:
            with open(temp_file.name, "w") as tf:
                ppd.writeFd(tf.fileno())

            with open(temp_file.name, "r") as tf:
                result = tf.read()

            hash = hashlib.md5(repr(result).encode('utf-8')).hexdigest()
            index = PluginRegistry.getInstance("ObjectIndex")

            new_file = os.path.join(dir, "%s.ppd" % hash)
            if new_file == custom_ppd_file:
                # nothing to to
                return {}

            if not is_server_ppd:
                # check if anyone else is using a file with this hash value and delete the old file if not
                query = {"_type": "GotoPrinter", "gotoPrinterPPD": "%s.ppd" % hash}
                if printer_cn is not None:
                    query["not_"] = {"cn": printer_cn}
                res = index.search(query, {"dn": 1})
                if len(res) == 0:
                    # delete file
                    os.unlink(custom_ppd_file)

            with open(new_file, "w") as f:
                f.write(result)

            return {
                "gotoPrinterPPD": ["%s/ppd/modified/%s.ppd" % (get_server_url(), hash)],
                "configured": [True]
            }

        except Exception as e:
            self.log.error(str(e))
            return {}
        finally:
            os.unlink(temp_file.name)
            if server_ppd is not None:
                os.unlink(server_ppd)
Exemplo n.º 51
0
    def __collect_user_configuration(self, client_id, users):
        """
        :param client_id: deviceUUID or hostname
        :param users: list of currently logged in users on the client
        """
        if isinstance(client_id, ObjectProxy):
            client = client_id
        else:
            client = self.__open_device(client_id, read_only=True)
        group = None
        index = PluginRegistry.getInstance("ObjectIndex")
        res = index.search({"_type": "GroupOfNames", "member": client.dn}, {"dn": 1})
        if len(res) > 0:
            group = ObjectProxy(res[0]["dn"], read_only=True)
        config = {}

        resolution = None
        if group is not None and group.is_extended_by("GotoEnvironment") and group.gotoXResolution is not None:
            resolution = group.gotoXResolution

        if client.is_extended_by("GotoEnvironment") and client.gotoXResolution is not None:
            resolution = client.gotoXResolution

        release = None
        if client.is_extended_by("GotoMenu"):
            release = client.getReleaseName()
        elif group is not None and group.is_extended_by("ForemanHostGroup"):
            release = group.getReleaseName()
            parent_group = group
            while release is None and parent_group is not None and parent_group.parent_id is not None:
                res = index.search({"_type": "GroupOfNames", "extension": "ForemanHostGroup", "foremanGroupId": parent_group.parent_id}, {"dn": 1})
                if len(res) == 0:
                    break
                else:
                    parent_group = ObjectProxy(res[0]["dn"], read_only=True)
                    release = parent_group.getReleaseName()

        if release is None:
            self.log.error("no release found for client/user combination (%s/%s)" % (client_id, users))

        client_menu = None

        if hasattr(client, "gotoMenu") and client.gotoMenu is not None:
            client_menu = loads(client.gotoMenu)

        # collect users DNs
        query_result = index.search({"_type": "User", "uid": {"in_": users}}, {"dn": 1})
        for entry in query_result:
            user = ObjectProxy(entry["dn"], read_only=True)
            config[user.uid] = {}

            if release is not None:
                menus = []
                if client_menu is not None:
                    menus.append(client_menu)

                # get all groups the user is member of which have a menu for the given release
                query = {'_type': 'GroupOfNames', "member": user.dn, "extension": "GotoMenu", "gotoLsbName": release}

                for res in index.search(query, {"gotoMenu": 1}):
                    # collect user menus
                    for m in res.get("gotoMenu", []):
                        menus.append(loads(m))

                if len(menus):
                    user_menu = None
                    for menu_entry in menus:
                        if user_menu is None:
                            user_menu = self.get_submenu(menu_entry)
                        else:
                            self.merge_submenu(user_menu, self.get_submenu(menu_entry))
                    config[user.uid]["menu"] = user_menu

            # collect printer settings for user, starting with the clients printers
            settings = self.__collect_printer_settings(group)
            printer_names = [x["cn"] for x in settings["printers"]]
            # get all GroupOfNames with GotoEnvironment the user or client is member of
            for res in index.search({'_type': 'GroupOfNames', "member": {"in_": [user.dn, client.dn]}, "extension": "GotoEnvironment"},
                                    {"dn": 1}):
                user_group = ObjectProxy(res["dn"], read_only=True)
                if group is not None and user_group.dn == group.dn:
                    # this group has already been handled
                    continue
                s = self.__collect_printer_settings(user_group)

                if user_group.gotoXResolution is not None:
                    resolution = user_group.gotoXResolution

                for p in s["printers"]:
                    if p["cn"] not in printer_names:
                        settings["printers"].append(p)
                        printer_names.append(p["cn"])

                if s["defaultPrinter"] is not None:
                    settings["defaultPrinter"] = s["defaultPrinter"]

            # override group environment settings if the client has one
            s = self.__collect_printer_settings(client)
            if len(s["printers"]) > 0:
                settings["printers"] = s["printers"]
                settings["defaultPrinter"] = s["defaultPrinter"]

            if user.is_extended_by("GosaAccount") and user.gosaDefaultPrinter is not None:
                # check if the users default printer is send to the client
                found = False
                for printer_settings in settings["printers"]:
                    if printer_settings["cn"] == user.gosaDefaultPrinter:
                        found = True
                        break

                def process(res):
                    if len(res) == 0:
                        self.log.warning("users defaultPrinter not found: %s" % user.gosaDefaultPrinter)
                        return None
                    elif len(res) == 1:
                        # add this one to the result set
                        printer = ObjectProxy(res[0]["dn"], read_only=True)
                        p_conf = {}
                        for attr in self.printer_attributes:
                            p_conf[attr] = getattr(printer, attr)
                        return p_conf
                    return False

                if found is False:
                    # find the printer and add it to the settings
                    res = index.search({"_type": "GotoPrinter", "cn": user.gosaDefaultPrinter}, {"dn": 1})
                    printer_config = process(res)
                    if printer_config is False:
                        # more than 1 printers found by this CN, try to look in the users subtree
                        res = index.search({
                            "_type": "GotoPrinter",
                            "cn": user.gosaDefaultPrinter,
                            "_adjusted_parent_dn": user.get_adjusted_parent_dn()
                        }, {"dn": 1})
                        printer_config = process(res)

                    if isinstance(printer_config, dict):
                        settings["printers"].append(printer_config)
                        settings["defaultPrinter"] = user.gosaDefaultPrinter
                    else:
                        self.log.warning("users defaultPrinter not found: %s" % user.gosaDefaultPrinter)
                else:
                    settings["defaultPrinter"] = user.gosaDefaultPrinter

            config[user.uid]["printer-setup"] = settings
            config[user.uid]["resolution"] = None

            if resolution is not None:
                config[user.uid]["resolution"] = [int(x) for x in resolution.split("x")]

            # TODO: collect and send login scripts to client
        return config
Exemplo n.º 52
0
Arquivo: main.py Projeto: peuter/gosa
 def __reload(self):
     if not os.path.exists(self.settings_file):
         self.__save_settings()
     else:
         with open(self.settings_file, "r") as f:
             self.__settings = loads(f.read())
Exemplo n.º 53
0
Arquivo: main.py Projeto: GOsa3/gosa
    def handle_request(self, request_handler):
        foreman = PluginRegistry.getInstance("Foreman")
        data = loads(request_handler.request.body)
        self.log.debug(data)

        # TODO disable hook logging to file
        with open("foreman-log.json", "a") as f:
            f.write("%s,\n" % dumps(data, indent=4, sort_keys=True))

        if data["event"] in ForemanHookReceiver.skip_next_event and data["object"] in ForemanHookReceiver.skip_next_event[data["event"]]:
            ForemanHookReceiver.skip_next_event[data["event"]].remove(data["object"])
            self.log.info("skipped '%s' event for object: '%s'" % (data["event"], data["object"]))
            return

        data_keys = list(data['data'].keys())
        if len(data_keys) == 1:
            type = data_keys[0]
        else:
            # no type given -> skipping this event as other might come with more information
            self.log.warning("skipping event '%s' for object '%s' as no type information is given in data: '%s'" % (data["event"],
                                                                                                                  data["object"],
                                                                                                                  data["data"]))
            return

        # search for real data
        if len(data['data'][type].keys()) == 1:
            # something like {data: 'host': {host: {...}}}
            #             or {data: 'discovered_host': {host: {...}}}
            payload_data = data['data'][type][list(data['data'][type].keys())[0]]
        else:
            payload_data = data['data'][type]

        if type == "operatingsystem":
            with make_session() as session:
                foreman.sync_release_name(payload_data, session, event=data['event'])
                session.commit()
                return

        factory = ObjectFactory.getInstance()
        foreman_type = type
        if type == "discovered_host":
            type = "host"

        object_types = factory.getObjectNamesWithBackendSetting("Foreman", "type", "%ss" % type)
        object_type = object_types[0] if len(object_types) else None

        backend_attributes = factory.getObjectBackendProperties(object_type) if object_type is not None else None
        self.log.debug("Hookevent: '%s' for '%s' (%s)" % (data['event'], data['object'], object_type))

        uuid_attribute = None
        if "Foreman" in backend_attributes:
            uuid_attribute = backend_attributes["Foreman"]["_uuidSourceAttribute"] \
                if '_uuidSourceAttribute' in backend_attributes["Foreman"] else backend_attributes["Foreman"]["_uuidAttribute"]

        ForemanBackend.modifier = "foreman"
        update_data = {}

        if data['event'] in ["update", "create"] and foreman_type == "host":
            id = payload_data["id"] if "id" in payload_data else None
            try:
                foreman.write_parameters(id if id is not None else data['object'])
            except:
                foreman.mark_for_parameter_setting(data['object'], {
                    "status": "created",
                    "use_id": id
                })

        if data['event'] == "after_commit" or data['event'] == "update" or data['event'] == "after_create" or data['event'] == "create":
            host = None
            if data['event'] == "update" and foreman_type == "host" and "mac" in payload_data and payload_data["mac"] is not None:
                # check if we have an discovered host for this mac
                index = PluginRegistry.getInstance("ObjectIndex")
                res = index.search({
                    "_type": "Device",
                    "extension": ["ForemanHost", "ieee802Device"],
                    "macAddress": payload_data["mac"],
                    "status": "discovered"
                }, {"dn": 1})

                if len(res):
                    self.log.debug("update received for existing host with dn: %s" % res[0]["dn"])
                    host = ObjectProxy(res[0]["dn"])

                    if foreman_type != "discovered_host" and host.is_extended_by("ForemanHost"):
                        host.status = "unknown"

            foreman_object = foreman.get_object(object_type, payload_data[uuid_attribute], create=host is None)
            if foreman_object and host:
                if foreman_object != host:
                    self.log.debug("using known host instead of creating a new one")
                    # host is the formerly discovered host, which might have been changed in GOsa for provisioning
                    # so we want to use this one, foreman_object is the joined one, so copy the credentials from foreman_object to host
                    if not host.is_extended_by("RegisteredDevice"):
                        host.extend("RegisteredDevice")
                    if not host.is_extended_by("simpleSecurityObject"):
                        host.extend("simpleSecurityObject")
                    host.deviceUUID = foreman_object.deviceUUID
                    host.userPassword = foreman_object.userPassword
                    host.otp = foreman_object.otp
                    host.cn = foreman_object.cn

                    # now delete the formerly joined host
                    foreman_object.remove()
                    foreman_object = host

            elif foreman_object is None and host is not None:
                foreman_object = host

            elif foreman_type == "discovered_host":
                self.log.debug("setting discovered state for %s" % payload_data[uuid_attribute])
                if not foreman_object.is_extended_by("ForemanHost"):
                    foreman_object.extend("ForemanHost")
                foreman_object.status = "discovered"

            if foreman_type == "host":
                old_build_state = foreman_object.build

            foreman.update_type(object_type, foreman_object, payload_data, uuid_attribute, update_data=update_data)
            if foreman_type == "host" and old_build_state is True and foreman_object.build is False and \
                            foreman_object.status == "ready":
                # send notification
                e = EventMaker()
                ev = e.Event(e.Notification(
                    e.Title(N_("Host ready")),
                    e.Body(N_("Host '%s' has been successfully build." % foreman_object.cn)),
                    e.Icon("@Ligature/pc"),
                    e.Timeout("10000")
                ))
                event_object = objectify.fromstring(etree.tostring(ev, pretty_print=True).decode('utf-8'))
                SseHandler.notify(event_object)

        elif data['event'] == "after_destroy":
            # print("Payload: %s" % payload_data)
            foreman.remove_type(object_type, payload_data[uuid_attribute])

            # because foreman sends the after_commit event after the after_destroy event
            # we need to skip this event, otherwise the host would be re-created
            if "after_commit" not in ForemanHookReceiver.skip_next_event:
                ForemanHookReceiver.skip_next_event["after_commit"] = [data['object']]
            else:
                ForemanHookReceiver.skip_next_event["after_commit"].append(data['object'])

            # add garbage collection for skip
            sobj = PluginRegistry.getInstance("SchedulerService")
            sobj.getScheduler().add_date_job(self.cleanup_event_skipper,
                                             datetime.datetime.now() + datetime.timedelta(minutes=1),
                                             args=("after_commit", data['object']),
                                             tag='_internal', jobstore='ram')

        else:
            self.log.info("unhandled hook event '%s' received for '%s'" % (data['event'], type))

        ForemanBackend.modifier = None
Exemplo n.º 54
0
for path, dirs, files in os.walk("src/gosa/backend/data"):
    for f in files:
            data_files.append(os.path.join(path[17:], f))

if sys.argv[1] == "import-from-json":
    from gosa.common.gjson import loads
    # import old template translations from json files
    translations = {}
    for translation_file in glob.glob(os.path.join("src", "gosa", "backend", "data", "templates", "i18n", "*", "*.json")):
        lang = os.path.basename(translation_file).split(".")[0]
        if lang == "en":
            continue
        if lang not in translations:
            translations[lang] = {}
        with open(translation_file) as f:
            translations[lang].update(loads(f.read()))

    # write them to the PO-Files

    for lang, strings in translations.items():
        po_file = os.path.join("src", "gosa", "backend", "locale", lang, "LC_MESSAGES", "messages.po")
        if os.path.exists(po_file):
            po = polib.pofile(po_file)
            changed = False
            for key, translation in strings.items():
                if translation is None:
                    continue
                entry = po.find(key)
                if entry is not None and entry.translated() is False:
                    entry.msgstr = translation
                    changed = True
Exemplo n.º 55
0
    def writePPD(self, printer_cn, server_ppd_file, custom_ppd_file, data):
        if self.client is None:
            return

        server_ppd = None
        dir = self.env.config.get("cups.spool", default="/tmp/spool")
        if not os.path.exists(dir):
            os.makedirs(dir)
        try:
            server_ppd = self.client.getServerPPD(server_ppd_file)
            is_server_ppd = True
            ppd = cups.PPD(server_ppd)
        except Exception as e:
            self.log.error(str(e))
            is_server_ppd = False

            if custom_ppd_file is not None:
                ppd = cups.PPD(os.path.join(dir, custom_ppd_file))
            else:
                raise PPDException(C.make_error('COULD_NOT_READ_SOURCE_PPD'))

        if isinstance(data, str):
            data = loads(data)

        # apply options
        for option_name, value in data.items():
            option = ppd.findOption(option_name)
            if option is not None:
                conflicts = ppd.markOption(option_name, value)
                if conflicts > 0:
                    raise PPDException(
                        C.make_error('OPTION_CONFLICT',
                                     option=option_name,
                                     value=value,
                                     conflicts=conflicts))
            else:
                raise PPDException(
                    C.make_error('OPTION_NOT_FOUND', option=option_name))

        # calculate hash value for new PPD

        temp_file = tempfile.NamedTemporaryFile(delete=False)
        try:
            with open(temp_file.name, "w") as tf:
                ppd.writeFd(tf.fileno())

            with open(temp_file.name, "r") as tf:
                result = tf.read()

            hash = hashlib.md5(repr(result).encode('utf-8')).hexdigest()
            index = PluginRegistry.getInstance("ObjectIndex")

            new_file = os.path.join(dir, "%s.ppd" % hash)
            if new_file == custom_ppd_file:
                # nothing to to
                return {}

            if not is_server_ppd:
                # check if anyone else is using a file with this hash value and delete the old file if not
                query = {
                    "_type": "GotoPrinter",
                    "gotoPrinterPPD": "%s.ppd" % hash
                }
                if printer_cn is not None:
                    query["not_"] = {"cn": printer_cn}
                res = index.search(query, {"dn": 1})
                if len(res) == 0:
                    # delete file
                    os.unlink(custom_ppd_file)

            with open(new_file, "w") as f:
                f.write(result)

            return {
                "gotoPrinterPPD":
                ["%s/ppd/modified/%s.ppd" % (get_server_url(), hash)],
                "configured": [True]
            }

        except Exception as e:
            self.log.error(str(e))
            return {}
        finally:
            os.unlink(temp_file.name)
            if server_ppd is not None:
                os.unlink(server_ppd)
Exemplo n.º 56
0
    def process(self, data):
        """
        Process an incoming JSONRPC request and dispatch it thru the
        *CommandRegistry*.

        ================= ==========================
        Parameter         Description
        ================= ==========================
        data              Incoming body data
        ================= ==========================

        ``Return``: varries
        """
        try:
            json = loads(data)
        except ValueError as e:
            raise ValueError(C.make_error("INVALID_JSON", data=str(e)))

        try:
            method = json['method']
            params = json['params']
            jid = json['id']
        except KeyError as e:
            raise ValueError(C.make_error("JSON_MISSING_PARAMETER"))

        if method.startswith('_'):
            raise tornado.web.HTTPError(403, "Bad method name %s: must not start with _" % method)
        if not isinstance(params, list) and not isinstance(params, dict):
            raise ValueError(C.make_error("PARAMETER_LIST_OR_DICT"))

        # Check if we're globally locked currently
        if GlobalLock.exists("scan_index"):
            raise FilterException(C.make_error('INDEXING', "base"))

        # execute command if it is allowed without login
        if method in no_login_commands:
            return self.dispatch(method, params, jid)

        cls = self.__class__

        twofa_manager = PluginRegistry.getInstance("TwoFactorAuthManager")

        # Create an authentication cookie on login
        if method == 'login':
            (user, password) = params

            # Check password and create session id on success
            sid = str(uuid.uuid1())
            result = {
                'state': AUTH_FAILED
            }

            lock_result = self.get_lock_result(user)
            if lock_result is not None:
                return dict(result=lock_result, error=None, id=jid)

            dn = self.authenticate(user, password)
            if dn is not False:
                # user and password matches so delete the user from observer list
                if user in cls.__dos_manager:
                    del cls.__dos_manager[user]

                cls.__session[sid] = {
                    'user': user,
                    'dn': dn,
                    'auth_state': None
                }
                self.set_secure_cookie('REMOTE_USER', user)
                self.set_secure_cookie('REMOTE_SESSION', sid)
                factor_method = twofa_manager.get_method_from_user(dn)
                if factor_method is None:
                    result['state'] = AUTH_SUCCESS
                    self.log.info("login succeeded for user '%s'" % user)
                elif factor_method == "otp":
                    result['state'] = AUTH_OTP_REQUIRED
                    self.log.info("login succeeded for user '%s', proceeding with OTP two-factor authentication" % user)
                elif factor_method == "u2f":
                    self.log.info("login succeeded for user '%s', proceeding with U2F two-factor authentication" % user)
                    result['state'] = AUTH_U2F_REQUIRED
                    result['u2f_data'] = twofa_manager.sign(user, dn)

                cls.__session[sid]['auth_state'] = result['state']

            else:
                # Remove current sid if present
                if not self.get_secure_cookie('REMOTE_SESSION') and sid in cls.__session:
                    del cls.__session[sid]

                self.log.error("login failed for user '%s'" % user)
                result['state'] = AUTH_FAILED

                # log login tries
                if user in cls.__dos_manager:
                    login_stats = cls.__dos_manager[user]
                    # stop counting after 6 tries to avoid "infinity" lock, the user is locked for more than an hour
                    if login_stats['count'] < 6:
                        login_stats['count'] += 1
                    login_stats['timestamp'] = time.time()
                    cls.__dos_manager[user] = login_stats
                else:
                    cls.__dos_manager[user] = {
                        'count': 1,
                        'timestamp': time.time(),
                        'ip': self.request.remote_ip
                    }
                lock_result = self.get_lock_result(user)
                if lock_result is not None:
                    return dict(result=lock_result, error=None, id=jid)

            return dict(result=result, error=None, id=jid)

        # Don't let calls pass beyond this point if we've no valid session ID
        if self.get_secure_cookie('REMOTE_SESSION') is None or not self.get_secure_cookie('REMOTE_SESSION').decode('ascii') in cls.__session:
            self.log.error("blocked unauthenticated call of method '%s'" % method)
            raise tornado.web.HTTPError(401, "Please use the login method to authorize yourself.")

        # Remove remote session on logout
        if method == 'logout':

            # Remove current sid if present
            if self.get_secure_cookie('REMOTE_SESSION') and self.get_secure_cookie('REMOTE_SESSION').decode('ascii') in cls.__session:
                del cls.__session[self.get_secure_cookie('REMOTE_SESSION').decode('ascii')]

            # Show logout message
            if self.get_secure_cookie('REMOTE_USER'):
                self.log.info("logout for user '%s' succeeded" % self.get_secure_cookie('REMOTE_USER'))

            self.clear_cookie("REMOTE_USER")
            self.clear_cookie("REMOTE_SESSION")
            return dict(result=True, error=None, id=jid)

        # check two-factor authentication
        sid = self.get_secure_cookie('REMOTE_SESSION').decode('ascii')
        if method == 'verify':
            (key,) = params
            if cls.__session[sid]['auth_state'] == AUTH_OTP_REQUIRED or cls.__session[sid]['auth_state'] == AUTH_U2F_REQUIRED:

                if twofa_manager.verify(cls.__session[sid]['user'], cls.__session[sid]['dn'], key):
                    cls.__session[sid]['auth_state'] = AUTH_SUCCESS
                    return dict(result={'state': AUTH_SUCCESS}, error=None, id=jid)
                else:
                    return dict(result={'state': AUTH_FAILED}, error=None, id=jid)

        if cls.__session[sid]['auth_state'] != AUTH_SUCCESS:
            raise tornado.web.HTTPError(401, "Please use the login method to authorize yourself.")

        return self.dispatch(method, params, jid)
Exemplo n.º 57
0
    def commandReceived(self, topic, message):
        """
        Process incoming commands, coming in with session and message
        information.

        ================= ==========================
        Parameter         Description
        ================= ==========================
        message           Received MQTT message
        ================= ==========================

        Incoming messages are coming from an
        :class:`gosa.common.components.mqtt_proxy.MQTTServiceProxy`. The command
        result is written to the '<domain>.client.<client-uuid>' queue.
        """
        err = None
        res = None
        name = None
        args = None
        id_ = ''

        response_topic = "%s/to-backend" % "/".join(topic.split("/")[0:4])

        try:
            req = loads(message)
        except Exception as e:
            err = str(e)
            self.log.error("ServiceRequestNotTranslatable: %s" % err)
            req = {'id': topic.split("/")[-2]}

        if err is None:
            try:
                id_ = req['id']
                name = req['method']
                args = req['params']

            except KeyError as e:
                self.log.error("KeyError: %s" % e)
                err = str(BadServiceRequest(message))

        self.log.debug("received call [%s] for %s: %s(%s)" %
                       (id_, topic, name, args))

        # Try to execute
        if err is None:
            try:
                res = self.__cr.dispatch(name, *args)
            except Exception as e:
                err = str(e)

                # Write exception to log
                exc_type, exc_value, exc_traceback = sys.exc_info()
                self.log.error(
                    traceback.format_exception(exc_type, exc_value,
                                               exc_traceback))

        self.log.debug("returning call [%s]: %s / %s" % (id_, res, err))

        response = dumps({"result": res, "id": id_})

        # Get rid of it...
        mqtt = PluginRegistry.getInstance('MQTTClientHandler')
        mqtt.send_message(response, topic=response_topic)
Exemplo n.º 58
0
    def test_rpc(self):
        service = PluginRegistry.getInstance("MQTTRPCService")
        request_uuid = uuid.uuid4()
        topic = "%s/proxy/fake_client_id/%s" % (
            Environment.getInstance().domain, request_uuid)

        with mock.patch.object(PluginRegistry.getInstance('CommandRegistry'), "dispatch") as m, \
                mock.patch.object(service.mqtt, "send_message") as mq:
            m.return_value = "fake_response"
            # call with wrong json
            service.handle_request(topic, "this is no json: 'string'")
            args, kwargs = mq.call_args
            response = loads(args[0])
            assert "error" in response
            assert kwargs["topic"] == "%s/response" % topic
            assert not m.called
            mq.reset_mock()

            # call without params
            service.handle_request(
                topic,
                dumps({
                    "id": "jsonrpc",
                    "method": "fakeCall",
                    "user": "******"
                }))
            args, kwargs = mq.call_args
            response = loads(args[0])
            assert "error" in response
            assert kwargs["topic"] == "%s/response" % topic
            assert not m.called

            # call with empty params
            service.handle_request(
                topic,
                dumps({
                    "id": "jsonrpc",
                    "method": "fakeCall",
                    "user": "******",
                    "session_id": "fake_session_id",
                    "params": []
                }))
            m.assert_called_with("admin", "fake_session_id", "fakeCall")
            args, kwargs = mq.call_args
            response = loads(args[0])
            assert "result" in response
            assert response["result"] == "fake_response"
            assert kwargs["topic"] == "%s/response" % topic
            mq.reset_mock()
            m.reset_mock()

            service.handle_request(
                topic,
                dumps({
                    "id": "jsonrpc",
                    "method": "fakeCall",
                    "user": "******",
                    "params": ["param1", "param2"]
                }))
            m.assert_called_with("admin", None, "fakeCall", "param1", "param2")
            args, kwargs = mq.call_args
            response = loads(args[0])
            assert "result" in response
            assert response["result"] == "fake_response"
            assert kwargs["topic"] == "%s/response" % topic

            mq.reset_mock()
            m.reset_mock()

            # call without user (client id taken as user)
            service.handle_request(
                topic,
                dumps({
                    "id": "jsonrpc",
                    "method": "fakeCall",
                    "params": []
                }))
            m.assert_called_with("fake_client_id", None, "fakeCall")
            args, kwargs = mq.call_args
            response = loads(args[0])
            assert "result" in response
            assert response["result"] == "fake_response"
            assert kwargs["topic"] == "%s/response" % topic