Exemple #1
0
 def bofhd_get_commands(self, session_id):
     """Build a dict of the commands available to the client."""
     session = BofhdSession(self.db, self.logger, session_id)
     ident = int(session.get_entity_id())
     if not ident:
         return {}
     try:
         return self.server.commands[ident]
     except KeyError:
         return self.__cache_commands(ident)
Exemple #2
0
 def bofhd_logout(self, session_id):
     """ The bofhd logout function. """
     session = BofhdSession(self.db, self.logger, session_id)
     try:
         session.clear_session()
         if session_id in self.server.sessions:
             del(self.server.sessions[session_id])
         self.db_commit()
     except Exception:
         self.db_rollback()
         raise
     return "OK"
Exemple #3
0
    def bofhd_run_command(self, session_id, cmd, *args):
        """Call command with session details.

        Execute the callable function (in the correct module) with the given
        name after mapping session_id to username

        """
        # First, drop the short-lived sessions FIXME: if this is too
        # CPU-intensive, introduce a timestamp in this class, and drop the
        # short-lived sessions ONLY if more than BofhdSession._short_timeout
        session = BofhdSession(self.db, self.logger)
        session.remove_short_timeout_sessions()
        self.db_commit()

        # Set up session object
        session = BofhdSession(self.db, self.logger, session_id,
                               self.client_address)
        entity_id = self.check_session_validity(session)
        self.db.cl_init(change_by=entity_id)

        self.logger.info(u'Run command: %s (%r) by %i', cmd, args, entity_id)
        if cmd not in self.server.classmap:
            raise CerebrumError("Illegal command {!r}".format(cmd))

        implementation = self.server.classmap[cmd](self.db, self.logger)
        func = getattr(implementation, cmd)

        # We know cmd is a safe statsd-prefix, since it's also a valid
        # attribute name
        stats_client = statsd.make_client(
            self.server.stats_config, prefix='bofhd.command.{0}'.format(cmd))

        with stats_client.pipeline() as stats:
            with stats.timer('time'):
                try:
                    has_tuples = False
                    for x in args:
                        if isinstance(x, (tuple, list)):
                            has_tuples = True
                            break
                    ret = []
                    self._run_command_with_tuples(func, session, args, ret)
                    if not has_tuples:
                        ret = ret[0]
                    self.db_commit()
                    # TBD: What should be returned if `args' contains tuple,
                    # indicating that `func` should be called multiple times?
                    stats.incr('success')
                    return self.db.pythonify_data(ret)
                except Exception:
                    self.db_rollback()
                    stats.incr('error')
                    raise
Exemple #4
0
    def bofhd_get_default_param(self, session_id, cmd, *args):
        """ Get default value for a parameter.

        Returns a string. The client should append '[<returned_string>]: ' to
        its prompt.

        Will either use the function defined in the command object, or in the
        corresponding parameter object.

        """
        session = BofhdSession(self.db, self.logger, session_id)
        cls, cmdObj = self.server.get_cmd_info(cmd)

        # If the client calls this method when no default function is defined,
        # it is a bug in the client.
        if cmdObj._default is not None:
            func = cmdObj._default
        else:
            func = cmdObj._params[len(args)]._default
            if func is None:
                return ""
        instance = cls(self.db, self.logger)
        return getattr(instance, func.__name__)(session, *args)
Exemple #5
0
    def bofhd_run_command(self, session_id, cmd, *args):
        """Call command with session details.

        Execute the callable function (in the correct module) with the given
        name after mapping session_id to username

        """
        # First, drop the short-lived sessions FIXME: if this is too
        # CPU-intensive, introduce a timestamp in this class, and drop the
        # short-lived sessions ONLY if more than BofhdSession._short_timeout
        session = BofhdSession(self.db, self.logger)
        session.remove_short_timeout_sessions()
        self.db_commit()

        # Set up session object
        session = BofhdSession(self.db, self.logger, session_id,
                               self.client_address)
        entity_id = self.check_session_validity(session)
        self.db.cl_init(change_by=entity_id)

        self.logger.debug(u'Run command: %s (%s) by %i', cmd, args, entity_id)
        if cmd not in self.server.classmap:
            raise CerebrumError(u"Illegal command '{!s}'".format(cmd))

        implementation = self.server.classmap[cmd](self.db, self.logger)
        func = getattr(implementation, cmd)

        try:
            has_tuples = False
            for x in args:
                if isinstance(x, (tuple, list)):
                    has_tuples = True
                    break
            ret = []
            self._run_command_with_tuples(func, session, args, ret)
            if not has_tuples:
                ret = ret[0]
            self.db_commit()
            # TBD: What should be returned if `args' contains tuple,
            # indicating that `func` should be called multiple times?
            return self.db.pythonify_data(ret)
        except Exception:
            self.db_rollback()
            raise
Exemple #6
0
 def bofhd_call_prompt_func(self, session_id, cmd, *args):
     """Return a dict with information on how to prompt for a
     parameter.  The dict can contain the following keys:
     - prompt : message string
     - help_ref : reference to help for this argument
     - last_arg : if this argument is the last.  If only this key
       is present, the client will send the command as it is.
     - default : default value
     - map : maps the user-entered value to a value that
       is returned to the server, typically when user selects from
       a list.  It is a list-of lists, where the inner list is like:
       (("%5s %s", 'foo', 'bar'), return-value).  The first row is
       used as header
     - raw : don't use map after all"""
     session = BofhdSession(self.db, self.logger, session_id,
                            self.client_address)
     cls, cmdObj = self.server.get_cmd_info(cmd)
     self.check_session_validity(session)
     if cmdObj._prompt_func is not None:
         self.logger.debug(u'prompt_func: %r', args)
         instance = cls(self.db, self.logger)
         return getattr(instance,
                        cmdObj._prompt_func.__name__)(session, *args)
     raise CerebrumError("Command %s has no prompt func" % (cmd,))
Exemple #7
0
    def bofhd_login(self, uname, password):
        """ Authenticate and create session.

        :param string uname: The username
        :param string password: The password, preferably in latin-1

        :return string:
            If authentication is successful, a session_id registered in
            BofhdSession is returned. This session_id can be used to run
            commands that requires authentication.

        :raise CerebrumError: If the user is not allowed to log in.

        """
        account = Factory.get('Account')(self.db)
        try:
            account.find_by_name(uname)
        except Errors.NotFoundError:
            if isinstance(uname, unicode):
                uname = uname.encode('utf-8')
            self.logger.info(
                u'Failed login for %s from %s: unknown username',
                uname, format_addr(self.client_address))
            raise CerebrumError("Unknown username or password")

        if isinstance(password, unicode):  # crypt.crypt don't like unicode
            # TODO: ideally we should not hardcode charset here.
            password = password.encode('iso8859-1')
        if not account.verify_auth(password):
            self.logger.info(
                u'Failed login for %s from %s: password mismatch',
                uname, format_addr(self.client_address))
            raise CerebrumError("Unknown username or password")

        # Check quarantines
        quarantines = self._get_quarantines(account)
        if quarantines:
            self.logger.info(
                'Failed login for %s from %s: quarantines %s',
                uname, format_addr(self.client_address),
                ', '.join(quarantines))
            raise CerebrumError(
                'User has active quarantines, login denied: %s' %
                ', '.join(quarantines))

        # Check expire_date
        if account.is_expired():
            self.logger.info(u'Failed login for %s from %s: account expired',
                             uname, format_addr(self.client_address))
            raise CerebrumError('User is expired, login denied')

        try:
            self.logger.info(u'Successful login for %s from %s',
                             uname, format_addr(self.client_address))
            session = BofhdSession(self.db, self.logger)
            session_id = session.set_authenticated_entity(
                account.entity_id, self.client_address[0])
            self.db_commit()
            self.server.sessions[session_id] = str(account.entity_id)
            return session_id
        except Exception:
            self.db_rollback()
            raise
Exemple #8
0
    def bofhd_login(self, uname, password):
        """ Authenticate and create session.

        :param string uname: The username
        :param string password: The password, preferably in latin-1

        :return string:
            If authentication is successful, a session_id registered in
            BofhdSession is returned. This session_id can be used to run
            commands that requires authentication.

        :raise CerebrumError: If the user is not allowed to log in.

        """
        stats_client = statsd.make_client(self.server.stats_config,
                                          prefix="bofhd.login")

        account = Factory.get('Account')(self.db)
        with stats_client.pipeline() as stats:
            try:
                account.find_by_name(uname)
            except Errors.NotFoundError:
                stats.incr('deny-creds')
                self.logger.info(
                    'Failed login for %r from %r: unknown username', uname,
                    format_addr(self.client_address))
                raise CerebrumError("Unknown username or password")

            if not account.verify_auth(password):
                stats.incr('deny-creds')
                self.logger.info(
                    'Failed login for %r from %r: password mismatch', uname,
                    format_addr(self.client_address))
                raise CerebrumError("Unknown username or password")

            # Check quarantines
            quarantines = self._get_quarantines(account)
            if quarantines:
                stats.incr('deny-quarantine')
                self.logger.info('Failed login for %r from %r: quarantines %s',
                                 uname, format_addr(self.client_address),
                                 quarantines)
                raise CerebrumError(
                    'User has active quarantines, login denied: %s' %
                    ', '.join(quarantines))

            # Check expire_date
            if account.is_expired():
                stats.incr('deny-expire')
                self.logger.info(
                    'Failed login for %r from %r: account expired', uname,
                    format_addr(self.client_address))
                raise CerebrumError('User is expired, login denied')

            try:
                self.logger.info('Successful login for %r from %r', uname,
                                 format_addr(self.client_address))
                session = BofhdSession(self.db, self.logger)
                session_id = session.set_authenticated_entity(
                    account.entity_id, self.client_address[0])
                self.db_commit()
                self.server.sessions[session_id] = str(account.entity_id)
                stats.incr('allow')
                return session_id
            except Exception:
                stats.incr('deny-error')
                self.db_rollback()
                raise