def test_reset_user_password_with_updated_user_email(self): # set user.last_login, ensures we get same/valid token # https://code.djangoproject.com/ticket/10265 self.user.last_login = now() self.user.save() new_password = "******" uid = urlsafe_base64_encode( force_bytes(self.user.pk)) mhv = default_token_generator token = mhv.make_token(self.user) data = {'token': token, 'new_password': new_password, 'uid': uid} # check that the token is valid valid_token = mhv.check_token(self.user, token) self.assertTrue(valid_token) # Update user email self.user.email = "*****@*****.**" self.user.save() update_partial_digests(self.user, "bobbob") # Token should be invalid as the email was updated invalid_token = mhv.check_token(self.user, token) self.assertFalse(invalid_token) request = self.factory.post('/', data=data) response = self.view(request) self.assertEqual(response.status_code, 400) self.assertTrue( 'Invalid token' in response.data['non_field_errors'][0])
def test_user_updates_email(self): view = ConnectViewSet.as_view( {'get': 'list'}, authentication_classes=(DigestAuthentication,)) auth = DigestAuth('*****@*****.**', 'bobbob') request = self._get_request_session_with_auth(view, auth) response = view(request) temp_token = TempToken.objects.get(user__username='******') self.data['temp_token'] = temp_token.key self.assertEqual(response.status_code, 200) self.assertEqual(response.data, self.data) self.user.email = "*****@*****.**" self.user.save() update_partial_digests(self.user, "bobbob") auth = DigestAuth('*****@*****.**', 'bobbob') request = self._get_request_session_with_auth(view, auth) response = view(request) temp_token = TempToken.objects.get(user__username='******') self.data['temp_token'] = temp_token.key self.data['email'] = '*****@*****.**' self.assertEqual(response.status_code, 200)
def test_user_updates_email(self): view = ConnectViewSet.as_view( {'get': 'list'}, authentication_classes=(DigestAuthentication,)) auth = DigestAuth('*****@*****.**', 'bobbob') request = self._get_request_session_with_auth(view, auth) response = view(request) temp_token = TempToken.objects.get(user__username='******') self.data['temp_token'] = temp_token.key self.assertEqual(response.status_code, 200) self.assertEqual(response.data, self.data) self.user.email = "*****@*****.**" self.user.save() update_partial_digests(self.user, "bobbob") auth = DigestAuth('*****@*****.**', 'bobbob') request = self._get_request_session_with_auth(view, auth) response = view(request) temp_token = TempToken.objects.get(user__username='******') self.data['temp_token'] = temp_token.key self.data['email'] = '*****@*****.**' self.assertEqual(response.status_code, 200)
def update(self, instance, validated_data): params = validated_data password = params.get("password1") email = params.get('email') # Check password if email is being updated if email and not password: raise serializers.ValidationError( _(u'Your password is required when updating your email ' u'address.')) if password and not instance.user.check_password(password): raise serializers.ValidationError(_(u'Invalid password')) # get user instance.user.email = email or instance.user.email instance.user.first_name = params.get('first_name', instance.user.first_name) instance.user.last_name = params.get('last_name', instance.user.last_name) instance.user.username = params.get('username', instance.user.username) instance.user.save() if password: # force django-digest to regenerate its stored partial digests update_partial_digests(instance.user, password) return super(UserProfileSerializer, self).update(instance, params)
def test_user_has_no_profile_bug(self): alice = User.objects.create(username='******') alice.set_password('alice') update_partial_digests(alice, "alice") view = ConnectViewSet.as_view( {'get': 'list'}, authentication_classes=(DigestAuthentication, )) auth = DigestAuth('alice', 'alice') request = self._get_request_session_with_auth(view, auth) response = view(request) self.assertEqual(response.status_code, 200)
def test_user_has_no_profile_bug(self): alice = User.objects.create(username='******') alice.set_password('alice') update_partial_digests(alice, "alice") view = ConnectViewSet.as_view( {'get': 'list'}, authentication_classes=(DigestAuthentication,)) auth = DigestAuth('alice', 'alice') request = self._get_request_session_with_auth(view, auth) response = view(request) self.assertEqual(response.status_code, 200)
def update(self, instance, validated_data): params = validated_data password = params.get("password1") email = params.get('email') # Check password if email is being updated if email and not password: raise serializers.ValidationError( _(u'Your password is required when updating your email ' u'address.')) if password and not instance.user.check_password(password): raise serializers.ValidationError(_(u'Invalid password')) # get user instance.user.email = email or instance.user.email instance.user.first_name = params.get('first_name', instance.user.first_name) instance.user.last_name = params.get('last_name', instance.user.last_name) instance.user.username = params.get('username', instance.user.username) instance.metadata = params.get('metadata', instance.metadata) instance.user.save() if email: instance.metadata.update({"is_email_verified": False}) instance.save() request = self.context.get('request') redirect_url = params.get('redirect_url') _send_verification_email(redirect_url, instance.user, request) if password: # force django-digest to regenerate its stored partial digests update_partial_digests(instance.user, password) return super(UserProfileSerializer, self).update(instance, params)
def update(self, instance, validated_data): params = validated_data password = params.get("password1") email = params.get('email') # Check password if email is being updated if email and not password: raise serializers.ValidationError( _(u'Your password is required when updating your email ' u'address.')) if password and not instance.user.check_password(password): raise serializers.ValidationError(_(u'Invalid password')) # get user instance.user.email = email or instance.user.email instance.user.first_name = params.get('first_name', instance.user.first_name) instance.user.last_name = params.get('last_name', instance.user.last_name) instance.user.username = params.get('username', instance.user.username) instance.user.save() if email: instance.metadata.update({"is_email_verified": False}) instance.save() request = self.context.get('request') redirect_url = params.get('redirect_url') _send_verification_email(redirect_url, instance.user, request) if password: # force django-digest to regenerate its stored partial digests update_partial_digests(instance.user, password) return super(UserProfileSerializer, self).update(instance, params)
def test_login_attempts(self, send_account_lockout_email): view = ConnectViewSet.as_view( {'get': 'list'}, authentication_classes=(DigestAuthentication, )) auth = DigestAuth('bob', 'bob') # clear cache cache.clear() request = self._get_request_session_with_auth(view, auth) # first time it creates a cache response = view(request) self.assertEqual(response.status_code, 401) self.assertEqual( response.data['detail'], u"Invalid username/password. For security reasons, " u"after 9 more failed login attempts you'll have to " u"wait 30 minutes before trying again.") request_ip = request.META.get('REMOTE_ADDR') self.assertEqual( cache.get(safe_key(f'login_attempts-{request_ip}-bob')), 1) # cache value increments with subsequent attempts response = view(request) self.assertEqual(response.status_code, 401) self.assertEqual( response.data['detail'], u"Invalid username/password. For security reasons, " u"after 8 more failed login attempts you'll have to " u"wait 30 minutes before trying again.") self.assertEqual( cache.get(safe_key(f'login_attempts-{request_ip}-bob')), 2) # login attempts are tracked separately for other IPs request.META.update({'HTTP_X_REAL_IP': '5.6.7.8'}) response = view(request) self.assertEqual(response.status_code, 401) self.assertEqual( cache.get(safe_key(f'login_attempts-{request_ip}-bob')), 2) self.assertEqual(cache.get(safe_key('login_attempts-5.6.7.8-bob')), 1) # login_attempts doesn't increase with correct login auth = DigestAuth('bob', 'bobbob') request = self._get_request_session_with_auth(view, auth) response = view(request) self.assertEqual(response.status_code, 200) self.assertEqual( cache.get(safe_key(f'login_attempts-{request_ip}-bob')), 2) # lockout_user cache created upon fifth attempt auth = DigestAuth('bob', 'bob') request = self._get_request_session_with_auth(view, auth) self.assertFalse(send_account_lockout_email.called) cache.set(safe_key(f'login_attempts-{request_ip}-bob'), 9) self.assertIsNone(cache.get(safe_key(f'lockout_ip-{request_ip}-bob'))) response = view(request) self.assertEqual(response.status_code, 401) self.assertEqual( response.data['detail'], u"Locked out. Too many wrong username/password " u"attempts. Try again in 30 minutes.") self.assertEqual( cache.get(safe_key(f'login_attempts-{request_ip}-bob')), 10) self.assertIsNotNone( cache.get(safe_key(f'lockout_ip-{request_ip}-bob'))) lockout = datetime.strptime( cache.get(safe_key(f'lockout_ip-{request_ip}-bob')), '%Y-%m-%dT%H:%M:%S') self.assertIsInstance(lockout, datetime) # email sent upon limit being reached with right arguments subject_path = 'account_lockout/lockout_email_subject.txt' self.assertTrue(send_account_lockout_email.called) email_subject = render_to_string(subject_path) self.assertIn(email_subject, send_account_lockout_email.call_args[1]['args']) self.assertEqual(send_account_lockout_email.call_count, 2, "Called twice") # subsequent login fails after lockout even with correct credentials auth = DigestAuth('bob', 'bobbob') request = self._get_request_session_with_auth(view, auth) response = view(request) self.assertEqual(response.status_code, 401) self.assertEqual( response.data['detail'], u"Locked out. Too many wrong username/password " u"attempts. Try again in 30 minutes.") # Other users on same IP not locked out alice = User.objects.create(username='******') alice.set_password('alice') update_partial_digests(alice, "alice") auth = DigestAuth('alice', 'alice') request = self._get_request_session_with_auth(view, auth) response = view(request) self.assertEqual(response.status_code, 200) self.assertEqual(request.META.get('REMOTE_ADDR'), request_ip) # clear cache cache.clear()