def testNonExistentValidUser(self): logger.debug('Running testNonExistentValidUser') backends = getBackends() gau = totpcgi.GAUser('*****@*****.**', backends) with self.assertRaises(totpcgi.UserNotFound): gau.verify_token(555555)
def testInvalidUsername(self): logger.debug('Running testInvalidUsername') backends = getBackends() with self.assertRaisesRegex(totpcgi.VerifyFailed, 'invalid characters'): totpcgi.GAUser('../../etc/passwd', backends)
def testInvalidSecretParsing(self): logger.debug('Running testInvalidSecretParsing') backends = getBackends() gau = totpcgi.GAUser('invalid', backends) with self.assertRaises(totpcgi.UserSecretError): gau.verify_token(555555)
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
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')
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')
def getValidUser(): backends = getBackends() return totpcgi.GAUser('valid', backends)