def active_user_with_email_and_inactive_other_methods_otp(): user, created = User.objects.get_or_create( username='******', email='*****@*****.**', ) if created: user.set_password('secretkey'), user.is_active = True user.save() MFAMethod = apps.get_model('trench.MFAMethod') MFAMethod.objects.create( user=user, secret=create_secret(), is_primary=True, name='email', is_active=True, ) MFAMethod.objects.create( user=user, secret=create_secret(), is_primary=False, name='sms', is_active=False, ) MFAMethod.objects.create( user=user, secret=create_secret(), is_primary=False, name='app', is_active=False, ) return user
def setUp(self): self.UserModel = get_user_model() self.client = APIClient() self.client.credentials() self.user = self.UserModel.objects.create_user( email='*****@*****.**', password="******") self.user2 = self.UserModel.objects.create_user( email='*****@*****.**', password="******") MFAMethod = apps.get_model('trench.MFAMethod') MFAMethod.objects.create( user=self.user2, secret=create_secret(), is_primary=True, name='email', is_active=True, ) self.user3 = self.UserModel.objects.create_user( email='*****@*****.**', password="******") self.device3 = Device.objects.create( user=self.user3, address='test3.1', identity_key='abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd', registration_id=1234) PreKey.objects.create( device=self.device3, key_id=1, public_key='abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd') SignedPreKey.objects.create( device=self.device3, key_id=1, public_key='abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd', signature= 'abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd' )
def active_user_with_many_otp_methods(): user, created = User.objects.get_or_create( username='******', email='*****@*****.**', ) backup_codes = generate_backup_codes() encrypted_backup_codes = ','.join([make_password(_) for _ in backup_codes]) if created: user.set_password('secretkey'), user.is_active = True user.save() MFAMethod = apps.get_model('trench.MFAMethod') MFAMethod.objects.create( user=user, secret=create_secret(), is_primary=True, name='email', is_active=True, _backup_codes=encrypted_backup_codes, ) MFAMethod.objects.create( user=user, secret=create_secret(), is_primary=False, name='sms', is_active=True, _backup_codes=encrypted_backup_codes, ) MFAMethod.objects.create( user=user, secret=create_secret(), is_primary=False, name='app', is_active=True, _backup_codes=encrypted_backup_codes, ) MFAMethod.objects.create( user=user, is_primary=False, name='yubi', is_active=True, _backup_codes=encrypted_backup_codes, ) return user, backup_codes[0]
def create(self, validated_data): """ Creates new MFAMethod object for given user, sets it as inactive, and marks as primary if no other active MFAMethod exists for user. """ return MFAMethod.objects.get_or_create(user=self.user, name=self.context['name'], defaults={ 'secret': create_secret(), 'is_active': False, })
def test_2fa_integration(user, logged_in_client, client): mfa_activate_url = reverse("v0:mfa-activate", args=["app"]) # check that url present mfa_confirm = reverse("v0:mfa-activate-confirm", args=["app"]) mfa_backup_codes = reverse("v0:mfa-regenerate-codes", args=["app"]) mfa_deactivate = reverse("v0:mfa-deactivate", args=["app"]) # Step 1: activate MFA response = logged_in_client.post(mfa_activate_url) assert response.status_code == 200 qr_link = response.data.get("qr_link") assert qr_link assert MFAMethod.objects.filter(user=user).count() == 1 secret = create_secret() # Step 2: confirm MFA (mocked step) assert not MFAMethod.objects.filter( user=user, is_active=True, is_primary=True).exists() MFAMethod.objects.filter(user=user).update(secret=secret) response = logged_in_client.post(mfa_confirm, {"code": create_otp_code(secret)}) assert response.status_code == 200 assert response.data["backup_codes"] assert MFAMethod.objects.filter(user=user, is_active=True, is_primary=True).exists() # Step 3: trying to login payload = {"email": user.email, "password": TEST_PASSWORD} response = client.post(GENERATE_CODE_URL, payload) assert response.status_code == 200 ephemeral_token = response.data["ephemeral_token"] payload = { "ephemeral_token": ephemeral_token, "code": create_otp_code(secret) } # Step 4: login with otp data response = client.post(GENERATE_TOKEN_URL, payload) assert response.status_code == 200 assert response.data["access"] client.defaults["HTTP_AUTHORIZATION"] = f"Bearer {response.data['access']}" # Step 5: request backup codes response = client.post(mfa_backup_codes, {"code": create_otp_code(secret)}) assert response.status_code == 200 assert response.data["backup_codes"] # Step 6: deactivate code = response.data["backup_codes"][0] response = client.post(mfa_deactivate, {"code": code}) assert response.status_code == 204 assert MFAMethod.objects.filter(name="app").exists() assert not MFAMethod.objects.get(name="app").is_active
def test_djoser_token_login_fail(self): """The usual djoser token login fails (cannot avoid 2fa)""" MFAMethod = apps.get_model('trench.MFAMethod') MFAMethod.objects.create( user=self.user2, secret=create_secret(), is_primary=True, name='email', is_active=True, ) response = self.client.post('/v1/auth/login/', { "email": '*****@*****.**', "password": "******" }) self.assertEqual("ephemeral_token" in response.data, True) self.assertEqual("auth_token" in response.data, False)
def test_add_user_mfa(active_user): client = APIClient() login_request = login(active_user) client.credentials(HTTP_AUTHORIZATION=header_template.format( get_token_from_response(login_request))) secret = create_secret() response = client.post( path='/auth/email/activate/', data={ 'secret': secret, 'code': create_otp_code(secret), 'user': getattr( active_user, active_user.USERNAME_FIELD, ) }, format='json', ) assert response.status_code == 200
def active_user_with_sms_otp(): user, created = User.objects.get_or_create( username='******', email='*****@*****.**', phone_number='555-555-555' ) if created: user.set_password('secretkey'), user.is_active = True user.save() MFAMethod = apps.get_model('trench.MFAMethod') MFAMethod.objects.create( user=user, secret=create_secret(), is_primary=True, name='sms', is_active=True, ) return user
def active_user_with_backup_codes(): user, created = User.objects.get_or_create( username='******', email='*****@*****.**', ) if created: user.set_password('secretkey'), user.is_active = True user.save() MFAMethod = apps.get_model('trench.MFAMethod') MFAMethod.objects.create( user=user, secret=create_secret(), is_primary=True, name='email', is_active=True, backup_codes=generate_backup_codes(), ) return user