예제 #1
0
def fetch_user_data(env, req):
    acctmgr = AccountManager(env)
    guard = AccountGuard(env)
    accounts = {}
    for username in acctmgr.get_users():
        if req.perm.has_permission('ACCTMGR_USER_ADMIN'):
            url = req.href.admin('accounts', 'users', user=username)
        else:
            url = None
        accounts[username] = {'username': username, 'review_url': url}
        if guard.user_locked(username):
            accounts[username]['locked'] = True
            t_lock = guard.lock_time(username)
            if t_lock > 0:
                t_release = guard.pretty_release_time(req, username)
                accounts[username]['release_hint'] = _(
                        "Locked until %(t_release)s",
                        t_release=t_release)
    for acct, status in get_user_attribute(env, username=None,
                                           authenticated=None).iteritems():
        account = accounts.get(acct)
        if account is not None and 1 in status:
            # Only use attributes related to authenticated
            # accounts.
            account['name'] = status[1].get('name')
            account['email'] = status[1].get('email')
            if account['email']:
                account['email'] = Chrome(env).format_author(req,
                                                             account['email'])
    ts_seen = last_seen(env)
    if ts_seen is not None:
        for username, last_visit in ts_seen:
            account = accounts.get(username)
            if account and last_visit:
                account['last_visit'] = to_datetime(last_visit)
    return sorted(accounts.itervalues(), key=lambda acct: acct['username'])
예제 #2
0
def fetch_user_data(env, req):
    acctmgr = AccountManager(env)
    guard = AccountGuard(env)
    accounts = {}
    for username in acctmgr.get_users():
        if req.perm.has_permission('ACCTMGR_USER_ADMIN'):
            url = req.href.admin('accounts', 'users', user=username)
        else:
            url = None
        accounts[username] = {'username': username, 'review_url': url}
        if guard.user_locked(username):
            accounts[username]['locked'] = True
            t_lock = guard.lock_time(username)
            if t_lock > 0:
                t_release = guard.pretty_release_time(req, username)
                accounts[username]['release_hint'] = _(
                    "Locked until %(t_release)s", t_release=t_release)
    for acct, status in get_user_attribute(env,
                                           username=None,
                                           authenticated=None).iteritems():
        account = accounts.get(acct)
        if account is not None and 1 in status:
            # Only use attributes related to authenticated
            # accounts.
            account['name'] = status[1].get('name')
            account['email'] = status[1].get('email')
            if account['email']:
                account['email'] = Chrome(env).format_author(
                    req, account['email'])
    ts_seen = last_seen(env)
    if ts_seen is not None:
        for username, last_visit in ts_seen:
            account = accounts.get(username)
            if account and last_visit:
                account['last_visit'] = to_datetime(last_visit)
    return sorted(accounts.itervalues(), key=lambda acct: acct['username'])
예제 #3
0
class AccountGuardTestCase(unittest.TestCase):
    def setUp(self):
        self.env = EnvironmentStub(default_data=True,
                                   enable=['trac.*', 'acct_mgr.guard.*'])
        self.env.path = tempfile.mkdtemp()
        self.env.config.set('account-manager', 'login_attempt_max_count', 1)
        self.db = self.env.get_db_cnx()

        self.user = '******'
        self.session = self._create_session(self.user)
        self.guard = AccountGuard(self.env)

    def tearDown(self):
        self.db.close()
        # Really close db connections.
        self.env.shutdown()
        shutil.rmtree(self.env.path)

    # Helpers

    def _create_session(self, user, authenticated=1, name='', email=''):
        args = dict(username=user, name=name, email=email)
        incookie = Cookie()
        incookie['trac_session'] = '123456'
        req = Mock(authname=bool(authenticated) and user or 'anonymous',
                   args=args,
                   base_path='/',
                   chrome=dict(warnings=list()),
                   href=Mock(prefs=lambda x: None),
                   incookie=incookie,
                   outcookie=Cookie(),
                   redirect=lambda x: None)
        req.session = Session(self.env, req)
        req.session.save()
        return req.session

    def _mock_failed_attempt(self, requests=1):
        ipnr = '127.0.0.1'
        ts = to_timestamp(to_datetime(None))
        attempts = eval(self.session.get('failed_logins', '[]'))
        count = int(self.session.get('failed_logins_count', 0))
        lock_count = int(self.session.get('lock_count', 0))
        max = self.env.config.getint('account-manager',
                                     'login_attempt_max_count')
        for r in range(requests):
            attempts.append(dict(ipnr=ipnr, time=ts))
            count += 1
            # Assume, that every lock is enforced.
            if not count < max:
                lock_count += 1
        self.session['failed_logins'] = str(attempts)
        self.session['failed_logins_count'] = count
        self.session['lock_count'] = lock_count
        self.session.save()
        return ts

    # Tests

    def test_failed_count(self):
        ipnr = '127.0.0.1'

        # Won't track anonymous sessions and unknown accounts/users.
        self.assertEqual(self.guard.failed_count(None, ipnr), 0)

        # Regular account without failed attempts logged.
        user = self.user
        # Start without failed attempts logged, accumulating failed attempts.
        self.assertEqual(self.guard.failed_count(user, ipnr), 1)
        self.assertEqual(self.guard.failed_count(user, ipnr), 2)
        # Read failed attempts.
        self.assertEqual(self.guard.failed_count(user, ipnr, None), 2)
        # Reset failed attempts, returning deleted attemps.
        self.assertEqual(self.guard.failed_count(user, reset=True), 2)
        self.assertEqual(self.guard.failed_count(user, reset=None), 0)

    def test_functional(self):
        ipnr = '127.0.0.1'
        user = self.user

        # Regular account without failed attempts logged.
        self.assertEqual(self.guard.lock_count(user), 0)
        self.assertEqual(self.guard.lock_time(user), 0)
        self.assertEqual(self.guard.release_time(user), 0)
        self.assertEqual(self.guard.user_locked(user), False)

        # Log failed attempt - this time with the real method.
        self.assertEqual(self.guard.failed_count(user, ipnr), 1)
        # Mock acct_mgr.LoginModule.authenticate behavior.
        if self.guard.user_locked(user):
            self.guard.lock_count(user, 'up')

        self.assertEqual(self.guard.lock_count(user), 1)
        self.assertEqual(self.guard.lock_time(user), 0)
        self.assertEqual(self.guard.release_time(user), 0)
        self.assertEqual(self.guard.user_locked(user), True)
        # Switch to time lock.
        self.env.config.set('account-manager', 'user_lock_time', 2)
        self.assertTrue(self.guard.release_time(user) > 0)
        self.assertEqual(self.guard.user_locked(user), True)
        sleep(2)
        self.assertEqual(self.guard.user_locked(user), False)

        self.assertEqual(self.guard.lock_time(user), 2)
        self.assertEqual(self.guard.lock_time(user, True), 2)
        self.env.config.set('account-manager', 'user_lock_time_progression', 3)
        self.assertEqual(self.guard.lock_time(user, True), 6)
        # Switch-back to permanent locking.
        self.env.config.set('account-manager', 'user_lock_time', 0)
        self.assertEqual(self.guard.user_locked(user), True)

    def test_lock_count(self):
        user = self.user
        self.assertEqual(self.guard.lock_count(user), 0)
        # Validate helper method too.
        self._mock_failed_attempt()
        # Increment per failed login.
        self.assertEqual(self.guard.lock_count(user, 'set'), 2)
        self.assertEqual(self.guard.lock_count(user), 2)
        # Return updated value on reset as well.
        self.assertEqual(self.guard.lock_count(user, 'reset'), 0)

    def test_lock_time(self):
        self.env.config.set('account-manager', 'user_lock_time', 30)
        self.env.config.set('account-manager', 'user_lock_time_progression', 1)

        # Won't track anonymous sessions and unknown accounts/users.
        self.assertEqual(self.guard.lock_time(None), 0)

        # Regular account without failed attempts logged.
        user = self.user
        self.assertEqual(self.guard.lock_time(user), 30)
        self._mock_failed_attempt(5)
        # Fixed lock time, no progression, with default configuration values.
        self.assertEqual(self.guard.lock_time(user), 30)

        # Preview calculation.
        self.assertEqual(self.guard.lock_time(user, True), 30)
        # Progression with base 3.
        self.env.config.set('account-manager', 'user_lock_time_progression', 3)
        self.assertEqual(self.guard.lock_time(user, True), 30 * 3**5)
        self.env.config.set('account-manager', 'user_lock_max_time', 1800)
        self.assertEqual(self.guard.lock_time(user, True), 1800)

    def test_release_time(self):
        lock_time = 30
        self.env.config.set('account-manager', 'user_lock_time', lock_time)
        self.env.config.set('account-manager', 'user_lock_time_progression', 1)

        # Won't track anonymous sessions and unknown accounts/users.
        self.assertEqual(self.guard.release_time(None), None)

        # Regular account without failed attempts logged.
        user = self.user
        self.assertEqual(self.guard.release_time(user), None)
        # Account with failed attempts logged.
        release_ts = self._mock_failed_attempt() + lock_time
        self.assertEqual(self.guard.release_time(user), release_ts)
        release_ts = self._mock_failed_attempt() + lock_time
        self.assertEqual(self.guard.release_time(user), release_ts)

        # Permanently locked account.
        self.env.config.set('account-manager', 'user_lock_time', 0)
        self.assertEqual(self.guard.release_time(user), 0)

        # Result with locking disabled.
        self.env.config.set('account-manager', 'login_attempt_max_count', 0)
        self.env.config.set('account-manager', 'user_lock_time', 30)
        self.assertEqual(self.guard.release_time(user), None)

    def test_user_locked(self):
        # Won't track anonymous sessions and unknown accounts/users.
        for user in [None, 'anonymous']:
            self.assertEqual(self.guard.user_locked(user), None)
        # Regular account without failed attempts logged.
        user = self.user
        self.assertEqual(self.guard.user_locked(user), False)

        # Permanently locked account.
        self._mock_failed_attempt()
        self.assertEqual(self.guard.user_locked(user), True)
        # Result with locking disabled.
        self.env.config.set('account-manager', 'login_attempt_max_count', 0)
        self.assertEqual(self.guard.user_locked(user), None)
예제 #4
0
class AccountGuardTestCase(unittest.TestCase):
    def setUp(self):
        self.env = EnvironmentStub(default_data=True,
                                   enable=['trac.*', 'acct_mgr.guard.*'])
        self.env.path = tempfile.mkdtemp()
        self.env.config.set('account-manager', 'login_attempt_max_count', 1)

        self.user = '******'
        self.session = self._create_session(self.user)
        self.guard = AccountGuard(self.env)

    def tearDown(self):
        self.env.shutdown()
        shutil.rmtree(self.env.path)

    # Helpers

    def _create_session(self, user, authenticated=1, name='', email=''):
        args = dict(username=user, name=name, email=email)
        incookie = Cookie()
        incookie['trac_session'] = '123456'
        req = Mock(authname=bool(authenticated) and user or 'anonymous',
                   args=args, base_path='/',
                   chrome=dict(warnings=list()),
                   href=Mock(prefs=lambda x: None),
                   incookie=incookie, outcookie=Cookie(),
                   redirect=lambda x: None)
        req.session = Session(self.env, req)
        req.session.save()
        return req.session

    def _mock_failed_attempt(self, requests=1):
        ipnr = '127.0.0.1'
        ts = to_timestamp(to_datetime(None))
        attempts = eval(self.session.get('failed_logins', '[]'))
        count = int(self.session.get('failed_logins_count', 0))
        lock_count = int(self.session.get('lock_count', 0))
        max_ = self.env.config.getint('account-manager',
                                     'login_attempt_max_count')
        for r in range(requests):
            attempts.append(dict(ipnr=ipnr, time=ts))
            count += 1
            # Assume, that every lock is enforced.
            if not count < max_:
                lock_count += 1
        self.session['failed_logins'] = str(attempts)
        self.session['failed_logins_count'] = count
        self.session['lock_count'] = lock_count
        self.session.save()
        return ts

    # Tests

    def test_failed_count(self):
        ipnr = '127.0.0.1'

        # Won't track anonymous sessions and unknown accounts/users.
        self.assertEqual(self.guard.failed_count(None, ipnr), 0)

        # Regular account without failed attempts logged.
        user = self.user
        # Start without failed attempts logged, accumulating failed attempts.
        self.assertEqual(self.guard.failed_count(user, ipnr), 1)
        self.assertEqual(self.guard.failed_count(user, ipnr), 2)
        # Read failed attempts.
        self.assertEqual(self.guard.failed_count(user, ipnr, None), 2)
        # Reset failed attempts, returning deleted attemps.
        self.assertEqual(self.guard.failed_count(user, reset=True), 2)
        self.assertEqual(self.guard.failed_count(user, reset=None), 0)

    def test_functional(self):
        ipnr = '127.0.0.1'
        user = self.user

        # Regular account without failed attempts logged.
        self.assertEqual(self.guard.lock_count(user), 0)
        self.assertEqual(self.guard.lock_time(user), 0)
        self.assertEqual(self.guard.release_time(user), 0)
        self.assertEqual(self.guard.user_locked(user), False)

        # Log failed attempt - this time with the real method.
        self.assertEqual(self.guard.failed_count(user, ipnr), 1)
        # Mock acct_mgr.LoginModule.authenticate behavior.
        if self.guard.user_locked(user):
            self.guard.lock_count(user, 'up')

        self.assertEqual(self.guard.lock_count(user), 1)
        self.assertEqual(self.guard.lock_time(user), 0)
        self.assertEqual(self.guard.release_time(user), 0)
        self.assertEqual(self.guard.user_locked(user), True)
        # Switch to time lock.
        self.env.config.set('account-manager', 'user_lock_time', 2)
        self.assertTrue(self.guard.release_time(user) > 0)
        self.assertEqual(self.guard.user_locked(user), True)
        sleep(2)
        self.assertEqual(self.guard.user_locked(user), False)

        self.assertEqual(self.guard.lock_time(user), 2)
        self.assertEqual(self.guard.lock_time(user, True), 2)
        self.env.config.set('account-manager', 'user_lock_time_progression',
                            3)
        self.assertEqual(self.guard.lock_time(user, True), 6)
        # Switch-back to permanent locking.
        self.env.config.set('account-manager', 'user_lock_time', 0)
        self.assertEqual(self.guard.user_locked(user), True)

    def test_lock_count(self):
        user = self.user
        self.assertEqual(self.guard.lock_count(user), 0)
        # Validate helper method too.
        self._mock_failed_attempt()
        # Increment per failed login.
        self.assertEqual(self.guard.lock_count(user, 'set'), 2)
        self.assertEqual(self.guard.lock_count(user), 2)
        # Return updated value on reset as well.
        self.assertEqual(self.guard.lock_count(user, 'reset'), 0)

    def test_lock_time(self):
        self.env.config.set('account-manager', 'user_lock_time', 30)
        self.env.config.set('account-manager', 'user_lock_time_progression',
                            1)

        # Won't track anonymous sessions and unknown accounts/users.
        self.assertEqual(self.guard.lock_time(None), 0)

        # Regular account without failed attempts logged.
        user = self.user
        self.assertEqual(self.guard.lock_time(user), 30)
        self._mock_failed_attempt(5)
        # Fixed lock time, no progression, with default configuration values.
        self.assertEqual(self.guard.lock_time(user), 30)

        # Preview calculation.
        self.assertEqual(self.guard.lock_time(user, True), 30)
        # Progression with base 3.
        self.env.config.set('account-manager', 'user_lock_time_progression',
                            3)
        self.assertEqual(self.guard.lock_time(user, True), 30 * 3 ** 5)
        self.env.config.set('account-manager', 'user_lock_max_time', 1800)
        self.assertEqual(self.guard.lock_time(user, True), 1800)

    def test_release_time(self):
        lock_time = 30
        self.env.config.set('account-manager', 'user_lock_time', lock_time)
        self.env.config.set('account-manager', 'user_lock_time_progression',
                            1)

        # Won't track anonymous sessions and unknown accounts/users.
        self.assertEqual(self.guard.release_time(None), None)

        # Regular account without failed attempts logged.
        user = self.user
        self.assertEqual(self.guard.release_time(user), None)
        # Account with failed attempts logged.
        release_ts = self._mock_failed_attempt() + lock_time
        self.assertEqual(self.guard.release_time(user), release_ts)
        release_ts = self._mock_failed_attempt() + lock_time
        self.assertEqual(self.guard.release_time(user), release_ts)

        # Permanently locked account.
        self.env.config.set('account-manager', 'user_lock_time', 0)
        self.assertEqual(self.guard.release_time(user), 0)

        # Result with locking disabled.
        self.env.config.set('account-manager', 'login_attempt_max_count', 0)
        self.env.config.set('account-manager', 'user_lock_time', 30)
        self.assertEqual(self.guard.release_time(user), None)

    def test_user_locked(self):
        # Won't track anonymous sessions and unknown accounts/users.
        for user in [None, 'anonymous']:
            self.assertEqual(self.guard.user_locked(user), None)
        # Regular account without failed attempts logged.
        user = self.user
        self.assertEqual(self.guard.user_locked(user), False)

        # Permanently locked account.
        self._mock_failed_attempt()
        self.assertEqual(self.guard.user_locked(user), True)
        # Result with locking disabled.
        self.env.config.set('account-manager', 'login_attempt_max_count', 0)
        self.assertEqual(self.guard.user_locked(user), None)