def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) token = serializer.validated_data['token'] # get token validation time password_reset_token_validation_time = get_password_reset_token_expiry_time( ) # find token reset_password_token = ResetPasswordToken.objects.filter( key=token).first() if reset_password_token is None: return Response({'status': 'notfound'}, status=status.HTTP_404_NOT_FOUND) # check expiry date expiry_date = reset_password_token.created_at + timedelta( hours=password_reset_token_validation_time) if timezone.now() > expiry_date: # delete expired token reset_password_token.delete() return Response({'status': 'expired'}, status=status.HTTP_404_NOT_FOUND) return Response({'status': 'OK'})
def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) token = serializer.validated_data['token'] response_dict = dict({"status_code": None, "status": None, "message": None}) # get token validation time password_reset_token_validation_time = get_password_reset_token_expiry_time() # find token reset_password_token = ResetPasswordToken.objects.filter(key=token).first() if reset_password_token is None: message = get_response_message("TOKEN_NOT_FOUND") response_dict.update({"status_code": 404, "status": "notfound", "message": message}) return Response(response_dict, status=status.HTTP_404_NOT_FOUND) # check expiry date expiry_date = reset_password_token.created_at + timedelta(hours=password_reset_token_validation_time) if timezone.now() > expiry_date: # delete expired token reset_password_token.delete() message = get_response_message("TOKEN_EXPIRED") response_dict.update({"status_code": 401, 'status': 'expired', "message": message}) return Response(response_dict, status=status.HTTP_404_NOT_FOUND) message = get_response_message("TOKEN_VALID") response_dict.update({"status_code": 200, 'status': 'OK', "message": message}) return Response(response_dict)
def validate(self, data): token = data.get('token') # get token validation time password_reset_token_validation_time = get_password_reset_token_expiry_time( ) # find token try: reset_password_token = _get_object_or_404( models.ResetPasswordToken, key=token) except (TypeError, ValueError, ValidationError, Http404, models.ResetPasswordToken.DoesNotExist): raise Http404( _("The OTP password entered is not valid. Please check and try again." )) # check expiry date expiry_date = reset_password_token.created_at + timedelta( hours=password_reset_token_validation_time) if timezone.now() > expiry_date: # delete expired token reset_password_token.delete() raise Http404(_("The token has expired")) return data
def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) email = serializer.validated_data['email'] # before we continue, delete all existing expired tokens password_reset_token_validation_time = get_password_reset_token_expiry_time() # datetime.now minus expiry hours now_minus_expiry_time = timezone.now() - timedelta(hours=password_reset_token_validation_time) # delete all tokens where created_at < now - 24 hours clear_expired(now_minus_expiry_time) # find a user by email address (case insensitive search) users = User.objects.filter(**{'{}__iexact'.format(get_password_reset_lookup_field()): email}) active_user_found = False # iterate over all users and check if there is any user that is active # also check whether the password can be changed (is useable), as there could be users that are not allowed # to change their password (e.g., LDAP user) for user in users: if user.eligible_for_reset(): active_user_found = True # No active user found, raise a validation error # but not if DJANGO_REST_PASSWORDRESET_NO_INFORMATION_LEAKAGE == True if not active_user_found and not getattr(settings, 'DJANGO_REST_PASSWORDRESET_NO_INFORMATION_LEAKAGE', False): raise exceptions.ValidationError({ 'email': [_( "There is no active user associated with this e-mail address or the password can not be changed")], }) # last but not least: iterate over all users that are active and can change their password # and create a Reset Password Token and send a signal with the created token for user in users: if user.eligible_for_reset(): # define the token as none for now token = None # check if the user already has a token if user.password_reset_tokens.all().count() > 0: # yes, already has a token, re-use this token token = user.password_reset_tokens.all()[0] else: # no token exists, generate a new token token = ResetPasswordToken.objects.create( user=user, user_agent=request.META.get(HTTP_USER_AGENT_HEADER, ''), ip_address=request.META.get(HTTP_IP_ADDRESS_HEADER, ''), ) # send a signal that the password token was created # let whoever receives this signal handle sending the email for the password reset reset_password_token_created.send(sender=self.__class__, instance=self, reset_password_token=token) # done message = get_response_message("PASSWORD_REQUEST_ACCEPT") return Response({"status_code": 200, "status": "OK", "message": message})
def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) email = serializer.validated_data['email'] # before we continue, delete all existing expired tokens password_reset_token_validation_time = get_password_reset_token_expiry_time() # datetime.now minus expiry hours now_minus_expiry_time = timezone.now() - timedelta(hours=password_reset_token_validation_time) # delete all tokens where created_at < now - 24 hours clear_expired(now_minus_expiry_time) # find a user by email address (case insensitive search) users = User.objects.filter(email__iexact=email) active_user_found = False # iterate over all users and check if there is any user that is active # also check whether the password can be changed (is useable), as there could be users that are not allowed # to change their password (e.g., LDAP user) for user in users: if user.is_active and user.has_usable_password(): active_user_found = True # No active user found, raise a validation error if not active_user_found: raise exceptions.ValidationError({ 'email': [_( "There is no active user associated with this e-mail address or the password can not be changed")], }) # last but not least: iterate over all users that are active and can change their password # and create a Reset Password Token and send a signal with the created token for user in users: if user.is_active and user.has_usable_password(): # define the token as none for now token = None # check if the user already has a token if user.password_reset_tokens.all().count() > 0: # yes, already has a token, re-use this token token = user.password_reset_tokens.all()[0] else: # no token exists, generate a new token token = ResetPasswordToken.objects.create( user=user, user_agent=request.META.get('HTTP_USER_AGENT', getattr(settings, 'DJANGO_REST_PASSWORDRESET_HTTP_USER_AGENT', '')), ip_address=request.META.get('REMOTE_ADDR', getattr(settings, 'DJANGO_REST_PASSWORDRESET_REMOTE_ADDR', '')) ) # send a signal that the password token was created # let whoever receives this signal handle sending the email for the password reset reset_password_token_created.send(sender=self.__class__, instance=self, reset_password_token=token) # done return Response({'status': 'OK'})
def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) password = serializer.validated_data['password'] token = serializer.validated_data['token'] response_dict = dict({"status_code": None, "message": None, "status": None}) # get token validation time password_reset_token_validation_time = get_password_reset_token_expiry_time() # find token reset_password_token = ResetPasswordToken.objects.filter(key=token).first() if reset_password_token is None: message = get_response_message("TOKEN_NOT_FOUND") response_dict.update({"status_code": 404, 'status': 'notfound', "message": message}) return Response(response_dict, status=status.HTTP_404_NOT_FOUND) # check expiry date expiry_date = reset_password_token.created_at + timedelta(hours=password_reset_token_validation_time) if timezone.now() > expiry_date: # delete expired token reset_password_token.delete() message = get_response_message("TOKEN_EXPIRED") response_dict.update({"status_code": 404, 'status': 'expired', "message": message}) return Response(response_dict, status=status.HTTP_404_NOT_FOUND) # change users password (if we got to this code it means that the user is_active) if reset_password_token.user.eligible_for_reset(): pre_password_reset.send(sender=self.__class__, user=reset_password_token.user) try: # validate the password against existing validators validate_password( password, user=reset_password_token.user, password_validators=get_password_validators(settings.AUTH_PASSWORD_VALIDATORS) ) except ValidationError as e: # raise a validation error for the serializer raise exceptions.ValidationError({ 'password': e.messages }) reset_password_token.user.set_password(password) reset_password_token.user.save() post_password_reset.send(sender=self.__class__, user=reset_password_token.user) # Delete all password reset tokens for this user ResetPasswordToken.objects.filter(user=reset_password_token.user).delete() # done message = get_response_message("PASSWORD_CHANGED") response_dict.update({"status_code": 200, "status": "OK", "message": message}) return Response(response_dict)
def clear_expired_tokens(): """Function used to clear existing and expired tokens.""" password_reset_token_validation_time = ( get_password_reset_token_expiry_time()) # datetime.now minus expiry hours now_minus_expiry_time = timezone.now() - timedelta( hours=password_reset_token_validation_time) # delete all tokens where created_at < now - 24 hours clear_expired(now_minus_expiry_time)
def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) password = serializer.validated_data['password'] token = serializer.validated_data['token'] # get token validation time password_reset_token_validation_time = get_password_reset_token_expiry_time( ) # find token reset_password_token = ResetPasswordToken.objects.filter( key=token).first() if reset_password_token is None: return Response({'status': 'notfound'}, status=status.HTTP_404_NOT_FOUND) # check expiry date expiry_date = reset_password_token.created_at + timedelta( hours=password_reset_token_validation_time) if timezone.now() > expiry_date: # delete expired token reset_password_token.delete() return Response({'status': 'expired'}, status=status.HTTP_404_NOT_FOUND) # change users password if reset_password_token.user.has_usable_password(): pre_password_reset.send(sender=self.__class__, user=reset_password_token.user) try: # validate the password against existing validators validate_password(password, user=reset_password_token.user, password_validators=get_password_validators( settings.AUTH_PASSWORD_VALIDATORS)) except ValidationError as e: # raise a validation error for the serializer raise exceptions.ValidationError({'password': e.messages}) reset_password_token.user.set_password(password) reset_password_token.user.save() post_password_reset.send(sender=self.__class__, user=reset_password_token.user) # Delete all password reset tokens for this user ResetPasswordToken.objects.filter( user=reset_password_token.user).delete() return Response({'status': 'OK'})
def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) password = serializer.validated_data['password'] confirm = serializer.validated_data['confirm'] token = serializer.validated_data['token'] if password == confirm: # get token validation time password_reset_token_validation_time = get_password_reset_token_expiry_time() # find token reset_password_token = ResetPasswordToken.objects.filter(key=token).first() if reset_password_token is None: return Response({'Estado': 'No encontrado'}, status=status.HTTP_404_NOT_FOUND) # check expiry date expiry_date = reset_password_token.created_at + timedelta(hours=password_reset_token_validation_time) if timezone.now() > expiry_date: # delete expired token reset_password_token.delete() return Response({'Estado': 'Caducado'}, status=status.HTTP_404_NOT_FOUND) # change users password (if we got to this code it means that the user is_active) if reset_password_token.user.eligible_for_reset(): pre_password_reset.send(sender=self.__class__, user=reset_password_token.user) try: # validate the password against existing validators validate_password( password, user=reset_password_token.user, password_validators=get_password_validators(settings.AUTH_PASSWORD_VALIDATORS) ) except ValidationError as e: # raise a validation error for the serializer raise exceptions.ValidationError({ 'password': e.messages }) reset_password_token.user.set_password(password) reset_password_token.user.save() post_password_reset.send(sender=self.__class__, user=reset_password_token.user) # Delete all password reset tokens for this user ResetPasswordToken.objects.filter(user=reset_password_token.user).delete() return Response({'Estado': 'Contraseña modificada'}) else: return Response({'Estado': 'Contraseñas diferentes'})
def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) password = serializer.validated_data['new_password'] token = serializer.validated_data['token'] password_reset_token_validation_time = get_password_reset_token_expiry_time() reset_password_token = ResetPasswordToken.objects.filter( key=token).first() if reset_password_token is None: return Response({'status': 'notfound'}, status=status.HTTP_404_NOT_FOUND) expiry_date = reset_password_token.created_at + \ timedelta(hours=password_reset_token_validation_time) if timezone.now() > expiry_date: reset_password_token.delete() return Response({'status': 'expired'}, status=status.HTTP_404_NOT_FOUND) if reset_password_token.user.eligible_for_reset(): pre_password_reset.send( sender=self.__class__, user=reset_password_token.user) try: validate_password( password, user=reset_password_token.user, password_validators=get_password_validators( settings.AUTH_PASSWORD_VALIDATORS) ) except ValidationError as e: raise exceptions.ValidationError({ 'password': e.messages }) reset_password_token.user.set_password(password) reset_password_token.user.save() post_password_reset.send( sender=self.__class__, user=reset_password_token.user) ResetPasswordToken.objects.filter( user=reset_password_token.user).delete() return Response({'status': 'OK'})
def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) email = serializer.validated_data['email'] password_reset_token_validation_time = get_password_reset_token_expiry_time() now_minus_expiry_time = timezone.now( ) - timedelta(hours=password_reset_token_validation_time) clear_expired(now_minus_expiry_time) users = User.objects.filter( **{'{}__iexact'.format(get_password_reset_lookup_field()): email}) active_user_found = False for user in users: if user.eligible_for_reset(): active_user_found = True if not active_user_found and not getattr(settings, 'DJANGO_REST_PASSWORDRESET_NO_INFORMATION_LEAKAGE', False): raise exceptions.ValidationError({ 'email': [_( "There is no active user associated with this e-mail address or the password can not be changed")], }) for user in users: if user.eligible_for_reset(): token = None if user.password_reset_tokens.all().count() > 0: token = user.password_reset_tokens.all()[0] else: token = ResetPasswordToken.objects.create( user=user, user_agent=request.META.get( HTTP_USER_AGENT_HEADER, ''), ip_address=request.META.get( HTTP_IP_ADDRESS_HEADER, ''), ) reset_password_token_created.send( sender=self.__class__, instance=self, reset_password_token=token) return Response({'status': 'OK'})
def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) password = serializer.validated_data['password'] token = serializer.validated_data['token'] # get token validation time password_reset_token_validation_time = get_password_reset_token_expiry_time( ) # find token reset_password_token = ResetPasswordToken.objects.filter( key=token).first() if reset_password_token is None: return Response({'status': 'notfound'}, status=status.HTTP_404_NOT_FOUND) # check expiry date expiry_date = reset_password_token.created_at + timedelta( hours=password_reset_token_validation_time) if timezone.now() > expiry_date: # delete expired token reset_password_token.delete() return Response({'status': 'expired'}, status=status.HTTP_404_NOT_FOUND) # change users password if reset_password_token.user.has_usable_password(): pre_password_reset.send(sender=self.__class__, user=reset_password_token.user) reset_password_token.user.set_password(password) reset_password_token.user.save() post_password_reset.send(sender=self.__class__, user=reset_password_token.user) # Delete all password reset tokens for this user ResetPasswordToken.objects.filter( user=reset_password_token.user).delete() return Response({'status': 'OK'})
def password_reset_token_created( sender, # pylint: disable=unused-argument reset_password_token, *_args, **_kwargs): """Handles password reset tokens. When a token is created, an e-mail needs to be sent to the user. """ reset_password_base_url = urljoin(settings.BASE_SITE_URL, '/reset-password/confirm/') context = { 'current_user': reset_password_token.user, 'username': reset_password_token.user.username, 'email': reset_password_token.user.email, 'reset_password_url': f'{reset_password_base_url}?token={reset_password_token.key}', 'base_site_url': settings.BASE_SITE_URL, 'site_name': settings.DEFAULT_SITE_NAME, 'token_expiry_time': get_password_reset_token_expiry_time(), } email_html_message = render_to_string('email/user_reset_password.html', context) email_plaintext_message = render_to_string('email/user_reset_password.txt', context) msg = EmailMultiAlternatives( subject=f'Password reset for {settings.DEFAULT_SITE_NAME}', body=email_plaintext_message, from_email=settings.DEFAULT_FROM_EMAIL, bcc=[reset_password_token.user.email], headers={ 'From': f'{settings.DEFAULT_SITE_NAME} <{settings.DEFAULT_FROM_EMAIL}>', 'To': reset_password_token.user.email, }) msg.attach_alternative(email_html_message, 'text/html') msg.send()
def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) email = serializer.validated_data['email'] # before we continue, delete all existing expired tokens password_reset_token_validation_time = get_password_reset_token_expiry_time( ) # datetime.now minus expiry hours now_minus_expiry_time = timezone.now() - timedelta( hours=password_reset_token_validation_time) # delete all tokens where created_at < now - 24 hours clear_expired(now_minus_expiry_time) # find a user by email address (case insensitive search) users = User.objects.filter(email__iexact=email) active_user_found = False # iterate over all users and check if there is any user that is active # also check whether the password can be changed (is useable), as there could be users that are not allowed # to change their password (e.g., LDAP user) for user in users: if user.is_active and user.has_usable_password(): active_user_found = True # No active user found, raise a validation error if not active_user_found: raise exceptions.ValidationError({ 'email': [ _("There is no active user associated with this e-mail address or the password can not be changed" ) ], }) # last but not least: iterate over all users that are active and can change their password # and create a Reset Password Token and send a signal with the created token for user in users: if user.is_active and user.has_usable_password(): # define the token as none for now token = None # check if the user already has a token if user.password_reset_tokens.all().count() > 0: # yes, already has a token, re-use this token token = user.password_reset_tokens.all()[0] else: ip = request.META.get('REMOTE_ADDR', None) # REMOTE_ADDR may be blank if socket server or load balancer are used, causing an exception # HTTP_X_FORWARDED_FOR as a fallback would be acceptable, since it's for logging purposes # and not authentication (also hard to spoof if load balancer is configured corrrectly) if ip is None or ip == b'': ip = request.META['HTTP_X_FORWARDED_FOR'].split(',')[ 0] # grab the first entry # no token exists, generate a new token token = ResetPasswordToken.objects.create( user=user, user_agent=request.META['HTTP_USER_AGENT'], ip_address=ip or '127.0.0.1') # send a signal that the password token was created # let whoever receives this signal handle sending the email for the password reset reset_password_token_created.send(sender=self.__class__, instance=self, reset_password_token=token) # done return Response({'status': 'OK'})
def handle(self, *args, **options): # datetime.now minus expiry hours now_minus_expiry_time = timezone.now() - datetime.timedelta( hours=get_password_reset_token_expiry_time()) clear_expired(now_minus_expiry_time)
def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) password = serializer.validated_data['password'] token = serializer.validated_data['token'] register = serializer.validated_data['register'] # get token validation time password_reset_token_validation_time = get_password_reset_token_expiry_time( register_token=register) # find token reset_password_token = ResetPasswordToken.objects.filter( key=token).first() if reset_password_token is None: return Response({'status': 'notfound'}, status=status.HTTP_404_NOT_FOUND) # check expiry date expiry_date = reset_password_token.created_at + timedelta( hours=password_reset_token_validation_time) if timezone.now() > expiry_date: # delete expired token reset_password_token.delete() return Response({'status': 'expired'}, status=status.HTTP_404_NOT_FOUND) # change users password (if we got to this code it means that the user is_active) if reset_password_token.user.eligible_for_reset( register_token=register): pre_password_reset.send(sender=self.__class__, user=reset_password_token.user) try: # validate the password against existing validators validate_password(password, user=reset_password_token.user, password_validators=get_password_validators( settings.AUTH_PASSWORD_VALIDATORS)) except ValidationError as e: # raise a validation error for the serializer raise exceptions.ValidationError({'password': e.messages}) reset_password_token.user.set_password(password) reset_password_token.user.save() post_password_reset.send(sender=self.__class__, user=reset_password_token.user) # Log the user in refresh = RefreshToken.for_user(reset_password_token.user) # Delete all password reset tokens for this user ResetPasswordToken.objects.filter( user=reset_password_token.user).delete() return Response({ 'refresh': str(refresh), 'access': str(refresh.access_token), }) else: #User is ineligible for password reset return Response({'status': 'User ineligible for password reset'}, status=status.HTTP_403_FORBIDDEN)