Ejemplo n.º 1
0
 def authenticate(self, req):
     if req.method == 'POST' and req.path_info.startswith('/login') and \
             req.args.get('user_locked') is None:
         username = self._remote_user(req)
         acctmgr = AccountManager(self.env)
         guard = AccountGuard(self.env)
         if guard.login_attempt_max_count > 0:
             if username is None:
                 # Get user for failed authentication attempt.
                 f_user = req.args.get('username')
                 req.args['user_locked'] = False
                 # Log current failed login attempt.
                 guard.failed_count(f_user, req.remote_addr)
                 if guard.user_locked(f_user):
                     # Step up lock time prolongation only while locked.
                     guard.lock_count(f_user, 'up')
                     req.args['user_locked'] = True
             elif guard.user_locked(username):
                 req.args['user_locked'] = True
                 # Void successful login as long as user is locked.
                 username = None
             else:
                 req.args['user_locked'] = False
                 if req.args.get('failed_logins') is None:
                     # Reset failed login attempts counter.
                     req.args['failed_logins'] = guard.failed_count(
                         username, reset=True)
         else:
             req.args['user_locked'] = False
         if not 'REMOTE_USER' in req.environ or self.environ_auth_overwrite:
             if 'REMOTE_USER' in req.environ:
                 # Complain about another component setting environment
                 # variable for authenticated user.
                 self.env.log.warn("LoginModule.authenticate: "
                                   "'REMOTE_USER' was set to '%s'" %
                                   req.environ['REMOTE_USER'])
             self.env.log.debug("LoginModule.authenticate: Set "
                                "'REMOTE_USER' = '%s'" % username)
             req.environ['REMOTE_USER'] = username
     return auth.LoginModule.authenticate(self, req)
Ejemplo n.º 2
0
 def authenticate(self, req):
     if req.method == 'POST' and req.path_info.startswith('/login') and \
             req.args.get('user_locked') is None:
         user = self._remote_user(req)
         acctmgr = AccountManager(self.env)
         guard = AccountGuard(self.env)
         if guard.login_attempt_max_count > 0:
             if user is None:
                 # Get user for failed authentication attempt.
                 f_user = req.args.get('user')
                 req.args['user_locked'] = False
                 # Log current failed login attempt.
                 guard.failed_count(f_user, req.remote_addr)
                 if guard.user_locked(f_user):
                     # Step up lock time prolongation only while locked.
                     guard.lock_count(f_user, 'up')
                     req.args['user_locked'] = True
             elif guard.user_locked(user):
                 req.args['user_locked'] = True
                 # Void successful login as long as user is locked.
                 user = None
             else:
                 req.args['user_locked'] = False
                 if req.args.get('failed_logins') is None:
                     # Reset failed login attempts counter.
                     req.args['failed_logins'] = guard.failed_count(user,
                                                              reset=True)
         else:
             req.args['user_locked'] = False
         if not 'REMOTE_USER' in req.environ or self.environ_auth_overwrite:
             if 'REMOTE_USER' in req.environ:
                 # Complain about another component setting environment
                 # variable for authenticated user.
                 self.env.log.warn("LoginModule.authenticate: "
                                   "'REMOTE_USER' was set to '%s'"
                                   % req.environ['REMOTE_USER'])
             self.env.log.debug("LoginModule.authenticate: Set "
                                "'REMOTE_USER' = '%s'" % user)
             req.environ['REMOTE_USER'] = user
     return auth.LoginModule.authenticate(self, req)
Ejemplo n.º 3
0
 def authenticate(self, req):
     if req.method == 'POST' and req.path_info.startswith('/login'):
         user = self._remote_user(req)
         acctmgr = AccountManager(self.env)
         guard = AccountGuard(self.env)
         if guard.login_attempt_max_count > 0:
             if user is None:
                 if req.args.get('user_locked') is None:
                     # get user for failed authentication attempt
                     f_user = req.args.get('user')
                     req.args['user_locked'] = False
                     if acctmgr.user_known(f_user) is True:
                         if guard.user_locked(f_user) is False:
                             # log current failed login attempt
                             guard.failed_count(f_user, req.remote_addr)
                             if guard.user_locked(f_user) is True:
                                 # step up lock time prolongation
                                 # only when just triggering the lock
                                 guard.lock_count(f_user, 'up')
                                 req.args['user_locked'] = True
                         else:
                             # enforce lock
                             req.args['user_locked'] = True
             else:
                 if guard.user_locked(user) is not False:
                     req.args['user_locked'] = True
                     # void successful login as long as user is locked
                     user = None
                 else:
                     req.args['user_locked'] = False
                     if req.args.get('failed_logins') is None:
                         # Reset failed login attempts counter
                         req.args['failed_logins'] = guard.failed_count(
                             user, reset=True)
         if 'REMOTE_USER' not in req.environ:
             req.environ['REMOTE_USER'] = user
     return auth.LoginModule.authenticate(self, req)
Ejemplo n.º 4
0
 def authenticate(self, req):
     if req.method == 'POST' and req.path_info.startswith('/login'):
         user = self._remote_user(req)
         acctmgr = AccountManager(self.env)
         guard = AccountGuard(self.env)
         if guard.login_attempt_max_count > 0:
             if user is None:
                 if req.args.get('user_locked') is None:
                     # get user for failed authentication attempt
                     f_user = req.args.get('user')
                     req.args['user_locked'] = False
                     if user_known(self.env, f_user):
                         if guard.user_locked(f_user) is False:
                             # log current failed login attempt
                             guard.failed_count(f_user, req.remote_addr)
                             if guard.user_locked(f_user) is True:
                                 # step up lock time prolongation
                                 # only when just triggering the lock
                                 guard.lock_count(f_user, 'up')
                                 req.args['user_locked'] = True
                         else:
                             # enforce lock
                             req.args['user_locked'] = True
             else:
                 if guard.user_locked(user) is not False:
                     req.args['user_locked'] = True
                     # void successful login as long as user is locked
                     user = None
                 else:
                     req.args['user_locked'] = False
                     if req.args.get('failed_logins') is None:
                         # Reset failed login attempts counter
                         req.args['failed_logins'] = guard.failed_count(
                                                      user, reset = True)
         if 'REMOTE_USER' not in req.environ:
             req.environ['REMOTE_USER'] = user
     return auth.LoginModule.authenticate(self, req)
Ejemplo n.º 5
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)
Ejemplo n.º 6
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)