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)
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"
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
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)
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
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,))
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
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