def test_change_email_when_wrong_password(self): from pyotp import TOTP self.create_user() self.login() self.add_evidence_sms() self.generate_sms_code(self.principal) validation_token = ValidationToken.objects.create( identifier='email', identifier_value=self.email, principal=self.principal, type='email_change', ) code = (OneTimePasswordCredential.objects.last()) totp = TOTP(code.salt.decode()) data = { 'sms_code': totp.now(), 'password': '******', 'secret': validation_token.secret } response = self.client.put(self.email_change_insecure_url, data=data) self.assertResponseStatus(response, status.HTTP_400_BAD_REQUEST) self.assertListEqual( response.data.get('error').get('password'), ['password_invalid']) self.assertListEqual( response.data.get('details').get('password'), ['Password is incorrect'])
def __init__(self, token): """ :param token: the OTP token. """ TOTP.__init__(self, token) self.pin = None self.update()
def verify(self, user_name, object_dn, key): # Do we have read permissions for the requested attribute self.__check_acl(user_name, object_dn, "r") # Get the object for the given dn uuid = self.__dn_to_uuid(object_dn) factor_method = self.get_method_from_user(uuid) user_settings = self.__settings[uuid] if uuid in self.__settings else {} if factor_method == "otp": totp = TOTP(user_settings.get('otp_secret')) return totp.verify(key) elif factor_method == "u2f": challenge = user_settings.pop('_u2f_challenge_') data = loads(key) device, c, t = complete_authentication(challenge, data, [self.facet]) return { 'keyHandle': device['keyHandle'], 'touch': t, 'counter': c } elif factor_method is None: return True return False
def is_correct_two_factor_code(self, code: str) -> bool: """Verify that a TOTP/backup code is correct.""" if not self.two_factor_secret: raise ValueError("User does not have 2FA enabled") totp = TOTP(self.two_factor_secret) code = code.strip().replace(" ", "").lower() # some possible user input (such as unicode) can cause an error in the totp # library, catch that and treat it the same as an invalid code try: is_valid_code = totp.verify(code) except TypeError: is_valid_code = False if is_valid_code: return True elif self.two_factor_backup_codes and code in self.two_factor_backup_codes: # Need to set the attribute so SQLAlchemy knows it changed self.two_factor_backup_codes = [ backup_code for backup_code in self.two_factor_backup_codes if backup_code != code ] return True return False
def test_change_email_when_success(self): from pyotp import TOTP self.create_user() self.login() self.add_evidence_sms() self.generate_sms_code(self.principal) email_to_change = "*****@*****.**" validation_token = ValidationToken.objects.create( identifier='email', identifier_value=email_to_change, principal=self.principal, type='email_change', ) code = (OneTimePasswordCredential.objects.last()) totp = TOTP(code.salt.decode()) data = { 'otp_code': totp.now(), 'password': self.password, 'secret': validation_token.secret } response = self.client.put(self.email_change_insecure_url, data=data) changed_pricipal = Principal.objects.last() self.assertResponseStatus(response) self.assertEquals(changed_pricipal.email, email_to_change)
def verify(self, user_name, object_dn, key): # Do we have read permissions for the requested attribute self.__check_acl(user_name, object_dn, "r") # Get the object for the given dn uuid = self.__dn_to_uuid(object_dn) factor_method = self.get_method_from_user(uuid) user_settings = self.__settings[ uuid] if uuid in self.__settings else {} if factor_method == "otp": totp = TOTP(user_settings.get('otp_secret')) return totp.verify(key) elif factor_method == "u2f": challenge = user_settings.pop('_u2f_challenge_') data = loads(key) device, c, t = complete_authentication(challenge, data, [self.facet]) return {'keyHandle': device['keyHandle'], 'touch': t, 'counter': c} elif factor_method is None: return True return False
def test_password_change_secure(self): from talos.models import OneTimePasswordCredential from talos.models import Principal from pyotp import TOTP self.create_user() self.login() self.add_evidence_google() self.assertEqual(OneTimePasswordCredential.objects.all().count(), 1) google_otp_credential = OneTimePasswordCredential.objects.last() secret = google_otp_credential.salt totp = TOTP(secret) google_otp_code = totp.now() data = { 'password': self.password, 'new_password': '******', 'otp_code': google_otp_code } response = self.client.put(self.url, data, format='json') self.assertResponseStatus(response, status.HTTP_200_OK) principal = Principal.objects.last() self.assertFalse(principal.check_password(self.password)) self.assertTrue(principal.check_password('1234567'))
def verify(self, user_name, object_dn, key): # Do we have read permissions for the requested attribute self.__check_acl(user_name, object_dn, "r") # Get the object for the given dn user = ObjectProxy(object_dn) factor_method = self.get_method_from_user(user) user_settings = self.__settings[ user.uuid] if user.uuid in self.__settings else {} if factor_method == "otp": totp = TOTP(user_settings.get('otp_secret')) return totp.verify(key) elif factor_method == "u2f": devices = [ DeviceRegistration.wrap(device) for device in user_settings.get('_u2f_devices_', []) ] challenge = user_settings.pop('_u2f_challenge_') data = loads(key) c, t = verify_authenticate(devices, challenge, data, [self.facet]) return {'touch': t, 'counter': c} elif factor_method is None: return True return False
def auth(): if not current_user.can_admin: abort(404) form = TOTPForm() try: user_secret = UserMetadata.get((UserMetadata.uid == current_user.uid) & (UserMetadata.key == 'totp_secret')) except UserMetadata.DoesNotExist: return engine.get_template('admin/totp.html').render({ 'authform': form, 'error': _('No TOTP secret found.') }) if form.validate_on_submit(): totp = TOTP(user_secret.value) if totp.verify(form.totp.data): session['apriv'] = time.time() return redirect(url_for('admin.index')) else: return engine.get_template('admin/totp.html').render({ 'authform': form, 'error': _('Invalid or expired token.') }) return engine.get_template('admin/totp.html').render({ 'authform': form, 'error': None })
def index(): if request.method == "POST": totp = TOTP(app.config["TOTP_SECRET"]) if "authcode" not in request.form: flash("Missing OTP", 'error') return redirect(request.url) if not totp.verify(request.form["authcode"]): flash("Incorrect OTP", "error") return redirect(request.url) if not request.files: flash("No files field", "error") return redirect(request.url) files = (f for f in request.files.getlist("files") if f.filename != "") if not files: flash("No files specified", "error") return redirect(request.url) for file in files: file.save(os.path.join(app.config["UPLOAD_DIR"], file.filename)) flash("Files uploaded correctly!", "success") return redirect("/drop") return render_template("drop.html")
def verify(self, user_name, object_dn, key): # Do we have read permissions for the requested attribute self.__check_acl(user_name, object_dn, "r") # Get the object for the given dn user = ObjectProxy(object_dn) factor_method = self.get_method_from_user(user) user_settings = self.__settings[user.uuid] if user.uuid in self.__settings else {} if factor_method == "otp": totp = TOTP(user_settings.get('otp_secret')) return totp.verify(key) elif factor_method == "u2f": devices = [DeviceRegistration.wrap(device) for device in user_settings.get('_u2f_devices_', [])] challenge = user_settings.pop('_u2f_challenge_') data = loads(key) c, t = verify_authenticate(devices, challenge, data, [self.facet]) return { 'touch': t, 'counter': c } elif factor_method is None: return True return False
def main(): token = input("Please input your token found on your android: ") data = list(bytes.fromhex(token)) assert len(data) == len(masks) # xor every byte with masks for i in range(0, len(data)): b = data[i] m = masks[i] b = b ^ m data[i] = b data_str = bytes(data).decode() secret_hex = data_str[:40] serial = data_str[40:] # use base32 to encode the first 40 bytes to be used in totp secret = base64.b32encode(bytes.fromhex(secret_hex)).decode() from pyotp import TOTP totp = TOTP(secret, digits=8) key = totp.now() print(secret) print(serial) print(key) url = "otpauth://totp/{0}:{0}?secret={1}&issuer={0}&digits=8".format( serial, secret) print(url)
def otp(self, otp: str) -> None: updated = False # Some sites give the secret in chunks split by spaces for easy reading # lets strip those as they'll produce an invalid secret. otp = otp.replace(" ", "") if not otp and self._otp: # Delete existing self._otp = None self._element.delete_custom_property("otp") self.updated() elif self._otp and self._otp.secret != otp: # Changing an existing OTP self._otp.secret = otp updated = True elif otp: # Creating brand new OTP. self._otp = TOTP(otp, issuer=self.name) updated = True if updated: self._element.set_custom_property("otp", self._otp.provisioning_uri()) self.updated()
def test_user_change_password(journalist_app, test_journo): """Test that a journalist can successfully login after changing their password""" with journalist_app.test_client() as app: _login_user(app, test_journo) # change password new_pw = 'another correct horse battery staply long password' assert new_pw != test_journo['password'] # precondition app.post('/account/new-password', data=dict(password=new_pw, current_password=test_journo['password'], token=TOTP(test_journo['otp_secret']).now())) # logout app.get('/logout') # start a new client/context to be sure we've cleared the session with journalist_app.test_client() as app: # login with new credentials should redirect to index page with InstrumentedApp(journalist_app) as ins: resp = app.post('/login', data=dict(username=test_journo['username'], password=new_pw, token=TOTP( test_journo['otp_secret']).now())) ins.assert_redirects(resp, '/')
def get_otpauth_url(serial: str, secret: str) -> str: """ Get the OTPAuth URL for the serial/secret pair https://github.com/google/google-authenticator/wiki/Key-Uri-Format """ totp = TOTP(secret, digits=8) return totp.provisioning_uri(serial, issuer_name="Blizzard")
def __init__(self, log_to_file, bank_channel_id, bank_role_id, totp_secret): super().__init__() self._log_to_file = log_to_file self._bank_channel_id = bank_channel_id self._bank_role_id = bank_role_id self._totp = TOTP(totp_secret) self.bank_roles = [] self.bank_channels = []
def __init__(self, log_to_file, bank_channel_id, bank_role_id, guild_server_id, totp_secret): super().__init__() self._log_to_file = log_to_file self._bank_channel_id = bank_channel_id self._bank_role_id = bank_role_id self._guild_server_id = guild_server_id self._totp = TOTP(totp_secret)
def main(): parser = ArgumentParser(path.basename(__file__)) parser.add_argument('--source-url', required=True) parser.add_argument('--journo-url', required=True) args = parser.parse_args() totp = TOTP('JHCOGO7VCER3EJ4L') auth = UserPassOtp('journalist', 'WEjwn8ZyczDhQSK24YKM8C9a', totp.now()) client = Client(args.journo_url, auth)
def set_totp(self, totp_secret): """Set the secret for generating MFA tokens to authorize Args: totp_secret (str): The secret token set on an Application in the Gem Developer Console. """ self.totp = TOTP(totp_secret) return self
def create(self): """ Create a tfa code """ try: self._totp = TOTP(self._token) self._secret_code = self._totp.now() except Exception as e: Logger.error("Couldn't generate two factor code : %s" % str(e))
def __init__(self, master=None): super().__init__(master) self.master = master self.totp = TOTP(get_secret()) self.totp_qr = get_secret_qr(self.totp) self.create_widgets() self.pack() self.update_pin_label() self.set_scheduler()
def create(self): """ Create a tfa code """ try: self.totp = TOTP(self.secret_code) self.password = self.totp.now() except Exception as e: logging.error("Couldn't generate two factor code : %s" % str(e))
def __enable_otp(self, user): if user.uuid not in self.__settings: self.__settings[user.uuid] = {} user_settings = self.__settings[user.uuid] secret = random_base32() totp = TOTP(secret) user_settings['otp_secret'] = secret self.__save_settings() return totp.provisioning_uri("%s@%s.gosa" % (user.uid, self.env.domain))
def show(ctx: click.Context, serial: str, interactive: bool) -> None: secret = ctx.obj.get_secret(serial) totp = TOTP(secret, digits=8) if interactive: click.echo("Ctrl-C to exit") while True: token = totp.now() sys.stdout.write("\r" + token) sys.stdout.flush() sleep(1) else: click.echo(totp.now())
def test_2fa(self): """The authentication should be failed because otp is not correct.""" from pyotp import TOTP otp = TOTP(self.secret.secret) query = { "username": "******", "password": "******", "otp_auth": str((int(otp.now()) + 1) % 1000000).zfill(6) } form = self.form_cls(None, query) self.assertFalse(form.is_valid()) self.assertTrue(form.errors)
def validate_code(self, code): from pyotp import TOTP if not self.request.session.get('secret_key_activated', False): raise serializers.ValidationError( 'You did not activated google authenticator', code=constants.GOOGLE_OTP_NOT_ACTIVATED_CODE) totp = TOTP(self.request.session['temp_otp_secret_key']) if not totp.verify(code, valid_window=1): raise serializers.ValidationError( 'Code is incorrect', code=constants.GOOGLE_OTP_INVALID_CODE) return code
def OTP(request): getd = unquote(request.GET.get('key')) signerverify = signer.unsign(getd, max_age=int(settings.PYADSELFSERVICE_STOUT)) if request.method == 'POST': form = renderotp(request.POST) if form.is_valid(): base32 = calc_base32(signerverify) totp = TOTP(base32) otp = totp.verify(form.cleaned_data['otp'], valid_window=5) data = signer.sign(signerverify) if otp == True: return HttpResponseRedirect('/resetpass?key=' + quote(data)) return render(request, 'index.html', {'form': renderotp()})
def test_2fa(self): """2fa should be valid.""" from pyotp import TOTP otp = TOTP(self.secret.secret) query = { "username": "******", "password": "******", "otp_auth": otp.now() } form = self.form_cls(None, query) self.assertTrue(form.is_valid(), "Form is invalid: {}".format(dict(form.errors))) self.assertDictEqual(query, form.clean())
def token_print(secret, n): preferred_offset = 0 if time_left > 7 else 1 for i in range(n): totp = TOTP(secret) token = totp.at(cur_time, i) token_formatted = token[:3] + '-' + token[3:] if (i == preferred_offset): token_formatted = colored(token_formatted, "green") try: copy(token) except Exception as e: pass print(token_formatted)
def test_clear_evidences_for_other_users(self): from datetime import datetime, timedelta from talos.models import OneTimePasswordCredential from talos.models import Principal from talos.models import Session from django.db.models import Q from pyotp import TOTP self.create_user() self.login() self.add_evidence_sms() self.assertEqual(OneTimePasswordCredential.objects.all().count(), 1) sms_otp_credential = OneTimePasswordCredential.objects.last() totp = TOTP(sms_otp_credential.salt.decode()) sms_code = totp.now() data = { 'password': self.password, 'new_password': '******', 'otp_code': sms_code } Session.objects.create(principal=self.principal, evidences='evidences') Session.objects.create(principal=self.principal, evidences='evidences') # Add another Session where valid_till is invalid (less than current time) Session.objects.create(principal=self.principal, evidences='evidences', valid_till=datetime.now() - timedelta(hours=24)) self.assertEqual(4, Session.objects.all().count()) response = self.client.put(self.url, data, format='json') self.assertResponseStatus(response, status.HTTP_200_OK) principal = Principal.objects.last() self.assertFalse(principal.check_password(self.password)) self.assertTrue(principal.check_password('1234567')) # Two row has been updated correctly (principal, valid_till) self.assertEqual( 2, Session.objects.filter(principal=self.principal, evidences=None).count()) self.assertEqual( 2, Session.objects.filter(Q(principal=self.principal), ~Q(evidences=None)).count())
def authenticate(self, request=None, **kwargs): """Check form validity.""" django_version = tuple( [int(s) for s in django.get_version().split(".")]) otp_auth = kwargs.pop("otp_auth", None) auth_user = partial( super(OTPAuthenticationBackend, self).authenticate, **kwargs) user = auth_user() if django_version < (1, 11) else auth_user(request) if hasattr(user, "otp_secret"): auth_provider = TOTP(user.otp_secret.secret) if not auth_provider.verify(otp_auth): user = None return user
def get(self, request, totp): chatrooms = Chatroom.objects.all() for chatroom in chatrooms: salt = chatroom.salt validator = TOTP(salt) if validator.verify(totp): data = ChatroomSerializer(chatroom).data token = jwt.encode(data, SECRET_KEY) body = {"token": token} body.update( serializer_to_body(ChatroomSerializer, chatroom, "chatroom")) return Response(body, status=status.HTTP_200_OK) return Response(status=status.HTTP_403_FORBIDDEN)
def auth(userID,OTP,path = 'Unknow'): from pyotp import TOTP from setting import OTPAdminLOG, Log_t_format from time import strftime, localtime as now User = OTPKeys[int(userID)] OTPi = TOTP(User[1]) f = open(OTPAdminLOG,'a') if (OTPi.verify(OTP)): f.writelines( strftime(Log_t_format,now())+"\t"+path+"\tAuthencate Successful\n" ) f.close() return True else: f.writelines( strftime(Log_t_format,now())+"\t"+path+"\tAuthencate Failed!!!!\n" ) f.close() return False
class Code: password = None def __init__(self, secret_code): self.secret_code = secret_code self.create() @staticmethod def is_valid(code): """ Check if the secret code is a valid one """ try: b32decode(code, casefold=True) return True except (binascii.Error, ValueError): return False def create(self): """ Create a tfa code """ try: self.totp = TOTP(self.secret_code) self.password = self.totp.now() except Exception as e: logging.error("Couldn't generate two factor code : %s" % str(e)) def update(self): """ Update the code """ self.password = self.totp.now() def get_secret_code(self): try: if self.password: return self.password else: raise AttributeError except AttributeError as e: logging.error("Couldn't generate the code : %s " % str(e)) return None
class Application(Wrapper, Updatable): """Representation of a Gem integration. Attributes: api_token (str) totp (pyotp.TOTP): A TOTP MFA token generator (initialized with set_totp) users (round.Users): A collection of Users who have an active device authorization on this Application. """ def set_totp(self, totp_secret): """Set the secret for generating MFA tokens to authorize Args: totp_secret (str): The secret token set on an Application in the Gem Developer Console. """ self.totp = TOTP(totp_secret) return self def get_mfa(self): """Return the currently-valid MFA token for this application.""" token = str(self.totp.now()) # PyOTP doesn't pre-pad tokens shorter than 6 characters # ROTP does, so we have to. while len(token) < 6: token = '0{}'.format(token) return token def reset(self, *args): """Resets any of the tokens for this Application. Note that you may have to reauthenticate afterwards. Usage: application.reset('api_token') application.reset('api_token', 'totp_secret') Args: *args (list of str): one or more of ['api_token', 'subscription_token', 'totp_secret'] Returns: The Application. """ self.resource = self.resource.reset(list(args)) return self @property @cacheable def users(self): """Returned the cached Users associated with this application.""" return self.get_users() def get_users(self, fetch=True): """Return this Applications's users object, populating it if fetch is True.""" return Users(self.resource.users, self.client, populate=fetch) @property @cacheable def wallets(self): """Returned the cached Wallets associated with this application.""" return self.get_wallets() def get_wallets(self, fetch=False): """Return this Applications's wallets object, populating it if fetch is True.""" return Wallets( self.resource.wallets, self.client, populate=fetch, application=self) @property @cacheable def subscriptions(self): """Return the cached Subscriptions object for this Application.""" return self.get_subscriptions() def get_subscriptions(self, fetch=True): """Return this Application's subscriptions object, populating it if fetch is True.""" return Subscriptions( self.resource.subscriptions, self.client, populate=fetch) def wallet(self, key): return self.client.wallet(key, application=self) @property @cacheable def netki_domains(self): """Fetch and return an updated list of NetkiDomains inside this Application.""" return self.get_netki_domains() def get_netki_domains(self, fetch=False): """Return the Applications NetkiDomains object, populating it if fetch is True.""" return NetkiDomains( self.resource.netki_domains, self.client, populate=fetch)
from pyotp import TOTP import requests def run(token, outfile): print('running') payload = {'token': token} r = requests.post('http://127.0.0.1:8000/', payload) print(r.status_code) with open(outfile, 'w') as f: f.write(r.text) if(__name__ == '__main__'): totp = TOTP("longpassword2") run(totp.now(), 'success.html') run('666666', 'fail.html') run('', 'empty.html')
import argparse import os from pyotp import TOTP import subprocess import sys import time if (sys.version_info > (3, 0)): DEVNULL = subprocess.DEVNULL else: DEVNULL = open(os.devnull, 'wb') # The default url url = 'https://kmaddux.com/' key = 'longpassword2' totp = TOTP(key) parser = argparse.ArgumentParser(prog='advertise-url', description=__doc__) parser.add_argument("-u", "--url", nargs='?', const=url, type=str, default=url, help='URL to advertise.') parser.add_argument('-s', '--stop', action='store_true', help='Stop advertising url.') parser.add_argument("-v", "--verbose", action='store_true', help='Print lots of debug output.') options = parser.parse_args() url = options.url
class Application(Wrapper, Updatable): """Representation of a Gem integration. Attributes: api_token (str) totp (pyotp.TOTP): A TOTP MFA token generator (initialized with set_totp) users (round.Users): A collection of Users who have an active device authorization on this Application. """ def set_totp(self, totp_secret): """Set the secret for generating MFA tokens to authorize Args: totp_secret (str): The secret token set on an Application in the Gem Developer Console. """ self.totp = TOTP(totp_secret) return self def get_mfa(self): """Return the currently-valid MFA token for this application.""" return self.totp.now() def reset(self, *args): """Resets any of the tokens for this Application. Note that you may have to reauthenticate afterwards. Usage: application.reset('api_token') application.reset('api_token', 'totp_secret') Args: *args (list of str): one or more of ['api_token', 'subscription_token', 'totp_secret'] Returns: The Application. """ self.resource = self.resource.reset(list(args)) return self @property def users(self): if not hasattr(self, '_users'): users_resource = self.resource.users self._users = users.Users(users_resource, self.client) return self._users @property def wallets(self): """Fetch and return Wallets associated with this application.""" if not hasattr(self, '_wallets'): wallets_resource = self.resource.wallets self._wallets = Wallets(wallets_resource, self.client, self) return self._wallets @property def subscriptions(self): """Fetch and return Subscriptions associated with this account.""" if not hasattr(self, '_subscriptions'): subscriptions_resource = self.resource.subscriptions self._subscriptions = Subscriptions( subscriptions_resource, self.client) return self._subscriptions
def test_token(): totp = TOTP(SECRET, digits=8) assert totp.at(1347279358) == "93461643" assert totp.at(1347279359) == "93461643" assert totp.at(1347279360) == "86031001"