Example #1
0
    def testNonExistentValidUser(self):
        logger.debug('Running testNonExistentValidUser')

        backends = getBackends()

        gau = totpcgi.GAUser('*****@*****.**', backends)
        with self.assertRaises(totpcgi.UserNotFound):
            gau.verify_token(555555)
Example #2
0
    def testInvalidUsername(self):
        logger.debug('Running testInvalidUsername')

        backends = getBackends()

        with self.assertRaisesRegex(totpcgi.VerifyFailed,
                                    'invalid characters'):
            totpcgi.GAUser('../../etc/passwd', backends)
Example #3
0
    def testInvalidSecretParsing(self):
        logger.debug('Running testInvalidSecretParsing')

        backends = getBackends()

        gau = totpcgi.GAUser('invalid', backends)
        with self.assertRaises(totpcgi.UserSecretError):
            gau.verify_token(555555)
Example #4
0
def getValidUser():
    logger.debug('Setting up user valid')
    backends = getBackends()
    gau = totpcgi.GAUser('valid', backends)
    if SECRET_BACKEND == 'File':
        with open(os.path.join(secrets_dir, 'valid.totp'), 'r') as fh:
            logger.debug('valid.totp follows\n%s', fh.read())
    return gau
Example #5
0
    def testHOTPRateLimit(self):
        logger.debug('Running testHOTPRateLimit')

        backends = getBackends()
        # Save custom state for HOTP user, as some backends rely on it to trigger HOTP mode
        state = totpcgi.GAUserState()
        state.counter = 1
        setCustomState(state, 'hotp')

        gau = totpcgi.GAUser('hotp', backends)
        secret = backends.secret_backend.get_user_secret(gau.user)

        hotp = pyotp.HOTP(secret.otp.secret)
        token = hotp.at(1)
        self.assertEqual(gau.verify_token(token), 'Valid HOTP token used')
        # counter is now at 2

        token = '555555'

        # We now fail 4 times consecutively
        with self.assertRaisesRegex(totpcgi.VerifyFailed,
                                    'HOTP token failed to verify'):
            gau.verify_token(token)
        with self.assertRaisesRegex(totpcgi.VerifyFailed,
                                    'HOTP token failed to verify'):
            gau.verify_token(token)
        with self.assertRaisesRegex(totpcgi.VerifyFailed,
                                    'HOTP token failed to verify'):
            gau.verify_token(token)
        with self.assertRaisesRegex(totpcgi.VerifyFailed,
                                    'HOTP token failed to verify'):
            gau.verify_token(token)

        # We should now get a rate-limited error
        with self.assertRaisesRegex(totpcgi.VerifyFailed, 'Rate-limit'):
            gau.verify_token(token)

        # Same with a valid token
        with self.assertRaisesRegex(totpcgi.VerifyFailed, 'Rate-limit'):
            gau.verify_token(hotp.at(2))

        # Make sure we recover from rate-limiting correctly
        old_timestamp = secret.timestamp - (31 + (secret.rate_limit[1] * 10))
        state = totpcgi.GAUserState()
        state.fail_timestamps = [
            old_timestamp, old_timestamp, old_timestamp, old_timestamp
        ]
        state.counter = 2
        setCustomState(state, 'hotp')

        with self.assertRaisesRegex(totpcgi.VerifyFailed,
                                    'HOTP token failed to verify'):
            gau.verify_token(token)

        # Valid token should work, too
        setCustomState(state, 'hotp')
        self.assertEqual(gau.verify_token(hotp.at(2)), 'Valid HOTP token used')
        cleanState('hotp')
Example #6
0
    def testValidToken(self):
        logger.debug('Running testValidToken')

        gau = getValidUser()
        backends = getBackends()
        secret = backends.secret_backend.get_user_secret(gau.user)

        totp = pyotp.TOTP(secret.otp.secret)
        token = totp.now()
        self.assertEqual(gau.verify_token(token), 'Valid TOTP token used')

        # try using it again
        with self.assertRaisesRegexp(totpcgi.VerifyFailed, 'been used once'):
            gau.verify_token(token)

        # and again, to make sure it is preserved in state
        with self.assertRaisesRegexp(totpcgi.VerifyFailed, 'been used once'):
            gau.verify_token(token)

        gau = totpcgi.GAUser('hotp', backends)
        # Save custom state for HOTP user, as some backends rely on it to trigger HOTP mode
        state = totpcgi.GAUserState()
        state.counter = 0
        setCustomState(state, 'hotp')

        hotp = pyotp.HOTP(secret.otp.secret)
        token = hotp.at(0)
        self.assertEqual(gau.verify_token(token), 'Valid HOTP token used')

        # make sure the counter now validates at 1 and 2
        self.assertEqual(gau.verify_token(hotp.at(1)), 'Valid HOTP token used')
        self.assertEqual(gau.verify_token(hotp.at(2)), 'Valid HOTP token used')

        # make sure trying "1" or "2" fails now
        with self.assertRaisesRegexp(totpcgi.VerifyFailed, 'HOTP token failed to verify'):
            gau.verify_token(hotp.at(1))
        with self.assertRaisesRegexp(totpcgi.VerifyFailed, 'HOTP token failed to verify'):
            gau.verify_token(hotp.at(2))

        # but we're good to go at 3
        self.assertEqual(gau.verify_token(hotp.at(3)), 'Valid HOTP token used')

        # and we're good to go with 7, which is max window size
        self.assertEqual(gau.verify_token(hotp.at(7)), 'Valid HOTP token within window size used')

        # Trying with "5" should fail now
        with self.assertRaisesRegexp(totpcgi.VerifyFailed, 'HOTP token failed to verify'):
            gau.verify_token(hotp.at(5))

        # but we're good to go at 8
        self.assertEqual(gau.verify_token(hotp.at(8)), 'Valid HOTP token used')

        # should fail with 13, which is beyond window size of 9+3
        with self.assertRaisesRegexp(totpcgi.VerifyFailed, 'HOTP token failed to verify'):
            gau.verify_token(hotp.at(13))

        cleanState('hotp')
Example #7
0
def getValidUser():
    backends = getBackends()
    return totpcgi.GAUser('valid', backends)