def failed_count(self, user, ipnr=None, reset=False): """Report number of previously logged failed login attempts. Enforce login policy with regards to tracking of login attempts and user account lock behavior. Default `False` for reset value causes logging of another attempt. `None` value for reset just reads failed login attempts count. `True` value for reset triggers final log deletion. """ value = get_user_attribute(self.env, user, 1, 'failed_logins_count') count = value and int(value[user][1].get('failed_logins_count')) or 0 if reset is None: # Report failed attempts count only. return count if not reset: # Trigger the failed attempt logger. attempts = self.get_failed_log(user) log_length = len(attempts) if log_length > self.login_attempt_max_count: # Truncate attempts list preserving most recent events. del attempts[:(log_length - self.login_attempt_max_count)] attempts.append({'ipnr': ipnr, 'time': to_utimestamp(to_datetime(None))}) count += 1 # Update or create attempts counter and list. set_user_attribute(self.env, user, 'failed_logins', str(attempts)) set_user_attribute(self.env, user, 'failed_logins_count', count) self.log.debug("AcctMgr:failed_count(%s): %s" % (user, count)) else: # Delete existing attempts counter and list. del_user_attribute(self.env, user, 1, 'failed_logins') del_user_attribute(self.env, user, 1, 'failed_logins_count') # Delete the lock count too. self.lock_count(user, 'reset') return count
def lock_count(self, user, action='get'): """Count, log and report, how often in succession user account lock conditions have been met. This is the exponent for lock time prolongation calculation too. """ key = 'lock_count' if not action == 'reset': value = get_user_attribute(self.env, user, 1, key) count = value and int(value[user][1].get(key)) or 0 if not action == 'get': # Push and create or update cached count. count += 1 set_user_attribute(self.env, user, key, count) else: # Reset/delete lock count cache. del_user_attribute(self.env, user, 1, key) count = 0 return count
def failed_count(self, user, ipnr=None, reset=False): """Report number of previously logged failed login attempts. Enforce login policy with regards to tracking of login attempts and user account lock behavior. Default `False` for reset value causes logging of another attempt. `None` value for reset just reads failed login attempts count. `True` value for reset triggers final log deletion. """ if not user or not user_known(self.env, user): return 0 key = 'failed_logins_count' value = get_user_attribute(self.env, user, 1, key) count = value and user in value and int(value[user][1].get(key)) or 0 if reset is None: # Report failed attempts count only. return count if not reset: # Trigger the failed attempt logger. attempts = self.get_failed_log(user) log_length = len(attempts) if log_length > self.login_attempt_max_count: # Truncate attempts list preserving most recent events. del attempts[:(log_length - self.login_attempt_max_count)] attempts.append({ 'ipnr': ipnr, 'time': to_timestamp(to_datetime(None)) }) count += 1 # Update or create attempts counter and list. set_user_attribute(self.env, user, 'failed_logins', str(attempts)) set_user_attribute(self.env, user, key, count) self.log.debug("AccountGuard.failed_count(%s) = %s" % (user, count)) else: # Delete existing attempts counter and list. del_user_attribute(self.env, user, 1, 'failed_logins') del_user_attribute(self.env, user, 1, key) # Delete the lock count too. self.lock_count(user, 'reset') return count
def _do_db_cleanup(self, req): if req.perm.has_permission('ACCTMGR_ADMIN'): env = self.env changed = False # Get all data from 'session_attributes' db table. attr = get_user_attribute(self.env, username=None, authenticated=None) attrs = {} sel = req.args.get('sel') if req.args.get('purge') and sel is not None: sel = isinstance(sel, list) and sel or [sel] sel_len = len(sel) matched = [] for acct, states in attr.iteritems(): for state in states['id'].keys(): for elem, id in states[state]['id'].iteritems(): if id in sel: if acct in attrs.keys(): if state in attrs[acct].keys(): attrs[acct][state] \ .append(elem) else: attrs[acct][state] = [elem] else: attrs[acct] = {state: [elem]} matched.append(id) if len(matched) == sel_len: break if len(matched) == sel_len: break if len(matched) == sel_len: break for id in (frozenset(sel) - frozenset(matched)): for acct, states in attr.iteritems(): for state, id_ in states['id'].iteritems(): if id == id_: # Full account is marked, forget attributes. if acct in attrs.keys(): attrs[acct].update({state: []}) else: attrs[acct] = {state: []} matched.append(id) if len(matched) == sel_len: break if len(matched) == sel_len: break # DEVEL: for Python>2.4 better use defaultdict for counters del_count = {'acct': 0, 'attr': 0} for account, states in attrs.iteritems(): for state, elem in states.iteritems(): if len(elem) == 0: del_user_attribute(env, account, state) del_count['acct'] += 1 else: for attribute in elem: del_user_attribute(env, account, state, attribute) del_count['attr'] += 1 changed = True elif req.args.get('list'): req.redirect(req.href.admin('accounts', 'users')) if changed == True: # Update the dict after changes. attr = get_user_attribute(env, username=None, authenticated=None) data = {'_dgettext': dgettext} data.update(self._prepare_attrs(req, attr)) if req.args.get('purge') and sel is not None: accounts = attributes = '' n_plural=del_count['acct'] if n_plural > 0: accounts = tag.li(tag.span(tag(ngettext( "%(count)s account", "%(count)s accounts", n_plural, count=n_plural )))) n_plural=del_count['attr'] if n_plural > 0: attributes = tag.li(tag.span(tag(ngettext( "%(count)s account attribute", "%(count)s account attributes", n_plural, count=n_plural )))) data['result'] = tag(_("Successfully deleted:"), tag.ul(accounts, attributes)) add_stylesheet(req, 'acct_mgr/acct_mgr.css') return 'db_cleanup.html', data
def _do_config(self, req): stores = StoreOrder(stores=self.acctmgr.stores, list=self.acctmgr.password_store) if req.method == 'POST': if req.args.get('restart'): del_user_attribute(self.env, attribute='password_refreshed') req.redirect(req.href.admin('accounts', 'config', done='restart')) _setorder(req, stores) self.config.set('account-manager', 'password_store', ','.join(stores.get_enabled_store_names())) for store in stores.get_all_stores(): for attr, option in _getoptions(store): cls_name = store.__class__.__name__ newvalue = req.args.get('%s.%s' % (cls_name, attr)) self.log.debug("%s.%s: %s" % (cls_name, attr, newvalue)) if newvalue is not None: self.config.set(option.section, option.name, newvalue) self.config.save() self.config.set('account-manager', 'force_passwd_change', req.args.get('force_passwd_change', False)) self.config.set('account-manager', 'persistent_sessions', req.args.get('persistent_sessions', False)) self.config.set('account-manager', 'verify_email', req.args.get('verify_email', False)) self.config.set('account-manager', 'refresh_passwd', req.args.get('refresh_passwd', False)) self.config.save() sections = [] for store in self.acctmgr.stores: if store.__class__.__name__ == "ResetPwStore": # Exclude special store, that is used strictly internally and # inherits configuration from SessionStore anyway. continue options = [] for attr, option in _getoptions(store): error = None opt_val = None value = None try: opt_val = option.__get__(store, store) except AttributeError, e: self.env.log.error(e) error = _("""Error while reading configuration - Hint: Enable/install the required component.""") pass if opt_val: value = isinstance(opt_val, Component) and \ opt_val.__class__.__name__ or opt_val opt_sel = None try: interface = option.xtnpt.interface opt_sel = {'options': [], 'selected': None} except AttributeError: # No ExtensionOption / Interface undefined pass if opt_sel: for impl in option.xtnpt.extensions(self.env): extension = impl.__class__.__name__ opt_sel['options'].append(extension) if opt_val and extension == value: opt_sel['selected'] = extension if len(opt_sel['options']) == 0 and error: opt_sel['error'] = error value = opt_sel options.append( {'label': attr, 'name': '%s.%s' % (store.__class__.__name__, attr), 'value': value, 'doc': gettext(option.__doc__) }) continue sections.append( {'name': store.__class__.__name__, 'classname': store.__class__.__name__, 'order': stores[store], 'options' : options, }) continue
def _do_db_cleanup(self, req): if req.perm.has_permission('ACCTMGR_ADMIN'): env = self.env changed = False # Get all data from 'session_attributes' db table. attr = get_user_attribute(self.env, username=None, authenticated=None) attrs = {} sel = req.args.get('sel') if req.args.get('purge') and sel is not None: sel = isinstance(sel, list) and sel or [sel] sel_len = len(sel) matched = [] for acct, states in attr.iteritems(): for state in states['id'].keys(): for elem, id in states[state]['id'].iteritems(): if id in sel: if acct in attrs.keys(): if state in attrs[acct].keys(): attrs[acct][state] \ .append(elem) else: attrs[acct][state] = [elem] else: attrs[acct] = {state: [elem]} matched.append(id) if len(matched) == sel_len: break if len(matched) == sel_len: break if len(matched) == sel_len: break for id in (frozenset(sel) - frozenset(matched)): for acct, states in attr.iteritems(): for state, id_ in states['id'].iteritems(): if id == id_: # Full account is marked, forget attributes. if acct in attrs.keys(): attrs[acct].update({state: []}) else: attrs[acct] = {state: []} matched.append(id) if len(matched) == sel_len: break if len(matched) == sel_len: break # DEVEL: for Python>2.4 better use defaultdict for counters del_count = {'acct': 0, 'attr': 0} for account, states in attrs.iteritems(): for state, elem in states.iteritems(): if len(elem) == 0: del_user_attribute(env, account, state) del_count['acct'] += 1 else: for attribute in elem: del_user_attribute(env, account, state, attribute) del_count['attr'] += 1 changed = True elif req.args.get('list'): req.redirect(req.href.admin('accounts', 'users')) if changed == True: # Update the dict after changes. attr = get_user_attribute(env, username=None, authenticated=None) data = {'_dgettext': dgettext} data.update(self._prepare_attrs(req, attr)) if req.args.get('purge') and sel is not None: accounts = attributes = '' n_plural = del_count['acct'] if n_plural > 0: accounts = tag.li( tag.span( tag( ngettext("%(count)s account", "%(count)s accounts", n_plural, count=n_plural)))) n_plural = del_count['attr'] if n_plural > 0: attributes = tag.li( tag.span( tag( ngettext("%(count)s account attribute", "%(count)s account attributes", n_plural, count=n_plural)))) data['result'] = tag(_("Successfully deleted:"), tag.ul(accounts, attributes)) add_stylesheet(req, 'acct_mgr/acct_mgr.css') return 'db_cleanup.html', data
def _do_config(self, req): stores = StoreOrder(stores=self.acctmgr.stores, list=self.acctmgr.password_store) if req.method == 'POST': if req.args.get('restart'): del_user_attribute(self.env, attribute='password_refreshed') req.redirect( req.href.admin('accounts', 'config', done='restart')) _setorder(req, stores) self.config.set('account-manager', 'password_store', ','.join(stores.get_enabled_store_names())) for store in stores.get_all_stores(): for attr, option in _getoptions(store): cls_name = store.__class__.__name__ newvalue = req.args.get('%s.%s' % (cls_name, attr)) self.log.debug("%s.%s: %s" % (cls_name, attr, newvalue)) if newvalue is not None: self.config.set(option.section, option.name, newvalue) self.config.save() self.config.set('account-manager', 'force_passwd_change', req.args.get('force_passwd_change', False)) self.config.set('account-manager', 'persistent_sessions', req.args.get('persistent_sessions', False)) self.config.set('account-manager', 'verify_email', req.args.get('verify_email', False)) self.config.set('account-manager', 'refresh_passwd', req.args.get('refresh_passwd', False)) self.config.save() sections = [] for store in self.acctmgr.stores: if store.__class__.__name__ == "ResetPwStore": # Exclude special store, that is used strictly internally and # inherits configuration from SessionStore anyway. continue options = [] for attr, option in _getoptions(store): error = None opt_val = None value = None try: opt_val = option.__get__(store, store) except AttributeError, e: self.env.log.error(e) error = _("""Error while reading configuration - Hint: Enable/install the required component.""") pass if opt_val: value = isinstance(opt_val, Component) and \ opt_val.__class__.__name__ or opt_val opt_sel = None try: interface = option.xtnpt.interface opt_sel = {'options': [], 'selected': None} except AttributeError: # No ExtensionOption / Interface undefined pass if opt_sel: for impl in option.xtnpt.extensions(self.env): extension = impl.__class__.__name__ opt_sel['options'].append(extension) if opt_val and extension == value: opt_sel['selected'] = extension if len(opt_sel['options']) == 0 and error: opt_sel['error'] = error value = opt_sel options.append({ 'label': attr, 'name': '%s.%s' % (store.__class__.__name__, attr), 'value': value, 'doc': gettext(option.__doc__) }) continue sections.append({ 'name': store.__class__.__name__, 'classname': store.__class__.__name__, 'order': stores[store], 'options': options, }) continue