def _validate_password(password, username=None, email=None): """Validate the format of the user's password. Passwords cannot be the same as the username of the account, so we create a temp_user using the username and email to test the password against. This user is never saved. Arguments: password (unicode): The proposed password. username (unicode): The username associated with the user's account. email (unicode): The email associated with the user's account. Returns: None Raises: errors.AccountPasswordInvalid """ try: _validate_type(password, basestring, accounts.PASSWORD_BAD_TYPE_MSG) temp_user = User(username=username, email=email) if username else None validate_password(password, user=temp_user) except errors.AccountDataBadType as invalid_password_err: raise errors.AccountPasswordInvalid(text_type(invalid_password_err)) except ValidationError as validation_err: raise errors.AccountPasswordInvalid(' '.join(validation_err.messages))
def clean_password(self): """Enforce password policies (if applicable)""" password = self.cleaned_data["password"] if self.enforce_password_policy: validate_password(password, username=self.cleaned_data.get('username')) return password
def _validate_password(password, username=None): """Validate the format of the user's password. Passwords cannot be the same as the username of the account, so we take `username` as an argument. Arguments: password (unicode): The proposed password. username (unicode): The username associated with the user's account. Returns: None Raises: errors.AccountPasswordInvalid """ try: _validate_type(password, basestring, accounts.PASSWORD_BAD_TYPE_MSG) validate_password(password, username=username) except errors.AccountDataBadType as invalid_password_err: raise errors.AccountPasswordInvalid(text_type(invalid_password_err)) except ValidationError as validation_err: raise errors.AccountPasswordInvalid(validation_err.message)
def _validate_password(password, username=None, email=None): """Validate the format of the user's password. Passwords cannot be the same as the username of the account, so we create a temp_user using the username and email to test the password against. This user is never saved. Arguments: password (unicode): The proposed password. username (unicode): The username associated with the user's account. email (unicode): The email associated with the user's account. Returns: None Raises: errors.AccountPasswordInvalid """ try: _validate_type(password, six.string_types, accounts.PASSWORD_BAD_TYPE_MSG) temp_user = User(username=username, email=email) if username else None validate_password(password, user=temp_user) except errors.AccountDataBadType as invalid_password_err: raise errors.AccountPasswordInvalid(text_type(invalid_password_err)) except ValidationError as validation_err: raise errors.AccountPasswordInvalid(' '.join(validation_err.messages))
def _validate_password(password, username=None): """Validate the format of the user's password. Passwords cannot be the same as the username of the account, so we take `username` as an argument. Arguments: password (unicode): The proposed password. username (unicode): The username associated with the user's account. Returns: None Raises: errors.AccountPasswordInvalid """ try: _validate_type(password, basestring, accounts.PASSWORD_BAD_TYPE_MSG) validate_password(password, username=username) except errors.AccountDataBadType as invalid_password_err: raise errors.AccountPasswordInvalid(text_type(invalid_password_err)) except ValidationError as validation_err: raise errors.AccountPasswordInvalid(validation_err.message)
def test_validation_errors(self, password, msg): """ Tests validate_password error messages """ if msg is None: validate_password(password) else: with self.assertRaises(ValidationError) as cm: validate_password(password) self.assertIn(msg, cm.exception.message)
def test_validation_errors(self, password, msg): """ Tests validate_password error messages """ if msg is None: validate_password(password) else: with self.assertRaises(ValidationError) as cm: validate_password(password) self.assertIn(msg, cm.exception.message)
def post(self, request): old_password = request.POST.get('old_password', '') new_password1 = request.POST.get('new_password1', '') new_password2 = request.POST.get('new_password2', '') user = request.user password = new_password1 parameters_dict = { "old_password": old_password, "new_password1": new_password1, "new_password2": new_password2 } for (key, value) in parameters_dict.items(): if not value: return JsonResponse({ "success": False, "code": 400, "msg": _('Request parameter {key} missing!'.format(key=key)), }) if user.check_password(old_password): if new_password1 != new_password2: return JsonResponse({ 'success': False, 'code': 201, 'msg': _('New passwords do not match. Please try again.') }) try: validate_password(password, user=user) except ValidationError as err: return JsonResponse({ 'success': False, 'code': 202, 'msg': ' '.join(err.messages) }) user.set_password(password) user.save() return JsonResponse({ 'success': True, 'code': 200, 'msg': _('Password modified.') }) else: return JsonResponse({ 'success': False, 'code': 203, 'msg': _('Wrong password') })
def _check_user_compliance(user, password): """ Returns a boolean indicating whether or not the user is compliant with password policy rules. """ try: validate_password(password, user=user) return True except Exception: # pylint: disable=broad-except # If anything goes wrong, we should assume the password is not compliant but we don't necessarily # need to prevent login. return False
def _check_user_compliance(user, password): """ Returns a boolean indicating whether or not the user is compliant with password policy rules. """ try: validate_password(password, user=user, password_reset=False) return True except Exception: # pylint: disable=broad-except # If anything goes wrong, we should assume the password is not compliant but we don't necessarily # need to prevent login. return False
def clean_password(self): """Enforce password policies (if applicable)""" password = self.cleaned_data["password"] if not self.do_third_party_auth: # Creating a temporary user object to test password against username # This user should NOT be saved username = self.cleaned_data.get('username') email = self.cleaned_data.get('email') temp_user = User(username=username, email=email) if username else None validate_password(password, temp_user) return password
def clean_password(self): """Enforce password policies (if applicable)""" password = self.cleaned_data["password"] if not self.do_third_party_auth: # Creating a temporary user object to test password against username # This user should NOT be saved username = self.cleaned_data.get('username') email = self.cleaned_data.get('email') temp_user = User(username=username, email=email) if username else None validate_password(password, temp_user) return password
def _validate_password(self, password, request): try: validate_password(password, user=self.user) except ValidationError as err: context = { 'validlink': True, 'form': None, 'title': _('Password reset unsuccessful'), 'err_msg': ' '.join(err.messages), } context.update(self.platform_name) return TemplateResponse( request, 'registration/password_reset_confirm.html', context)
def test_ignore_reset_checks(self, mock_reuse): """ Test that we don't annoy user about compliance failures that only affect password resets """ user = UserFactory() password = '******' mock_reuse.return_value = False # Sanity check that normal validation would trip us up with self.assertRaises(SecurityPolicyError): validate_password(password, user=user) # Confirm that we don't trip on it self.assertTrue(_check_user_compliance(user, password))
def test_ignore_reset_checks(self, mock_reuse): """ Test that we don't annoy user about compliance failures that only affect password resets """ user = UserFactory() password = '******' mock_reuse.return_value = False # Sanity check that normal validation would trip us up with self.assertRaises(SecurityPolicyError): validate_password(password, user=user) # Confirm that we don't trip on it self.assertTrue(_check_user_compliance(user, password))
def validation_errors_checker(self, password, msg, user=None): """ This helper function is used to check the proper error messages are being displayed based on the password and validator. Parameters: password (unicode): the password to validate on user (django.contrib.auth.models.User): user object to use in validation. This is an optional parameter unless the validator requires a user object. msg (str): The expected ValidationError message """ if msg is None: validate_password(password, user) else: with self.assertRaises(ValidationError) as cm: validate_password(password, user) self.assertIn(msg, ' '.join(cm.exception.messages))
def validation_errors_checker(self, password, msg, user=None): """ This helper function is used to check the proper error messages are being displayed based on the password and validator. Parameters: password (unicode): the password to validate on user (django.contrib.auth.models.User): user object to use in validation. This is an optional parameter unless the validator requires a user object. msg (str): The expected ValidationError message """ if msg is None: validate_password(password, user) else: with self.assertRaises(ValidationError) as cm: validate_password(password, user) self.assertIn(msg, ' '.join(cm.exception.messages))
def password_reset_logistration(request, **kwargs): """Reset learner password using passed token and new credentials""" reset_status = False uidb36 = kwargs.get('uidb36') token = kwargs.get('token') has_required_values, uid_int = _check_token_has_required_values( uidb36, token) if not has_required_values: AUDIT_LOG.exception("Invalid password reset confirm token") return JsonResponse({'reset_status': reset_status}) request.POST = request.POST.copy() request.POST['new_password1'] = normalize_password( request.POST['new_password1']) request.POST['new_password2'] = normalize_password( request.POST['new_password2']) password = request.POST['new_password1'] try: user = User.objects.get(id=uid_int) if not default_token_generator.check_token(user, token): AUDIT_LOG.exception("Token validation failed") return JsonResponse({'reset_status': reset_status}) validate_password(password, user=user) form = SetPasswordForm(user, request.POST) if form.is_valid(): form.save() reset_status = True except ValidationError as err: AUDIT_LOG.exception("Password validation failed") error_status = { 'reset_status': reset_status, 'err_msg': ' '.join(err.messages) } return JsonResponse(error_status) except Exception: # pylint: disable=broad-except AUDIT_LOG.exception("Setting new password failed") return JsonResponse({'reset_status': reset_status})
def test_unicode_password(self): """ Tests that validate_password enforces unicode """ byte_str = b'Ёдно' unicode_str = u'Ёдно' # Sanity checks and demonstration of why this test is useful self.assertEqual(len(byte_str), 4) self.assertEqual(len(unicode_str), 1) self.assertEqual(password_min_length(), 2) # Test length check with self.assertRaises(ValidationError): validate_password(byte_str) validate_password(byte_str + byte_str) # Test badly encoded password with self.assertRaises(ValidationError) as cm: validate_password(b'\xff\xff') self.assertEquals('Invalid password.', cm.exception.message)
def test_unicode_password(self): """ Tests that validate_password enforces unicode """ byte_str = b'Ёдно' unicode_str = u'Ёдно' # Sanity checks and demonstration of why this test is useful self.assertEqual(len(byte_str), 4) self.assertEqual(len(unicode_str), 1) self.assertEqual(password_min_length(), 2) # Test length check with self.assertRaises(ValidationError): validate_password(byte_str) validate_password(byte_str + byte_str) # Test badly encoded password with self.assertRaises(ValidationError) as cm: validate_password(b'\xff\xff') self.assertEquals('Invalid password.', cm.exception.message)
def password_reset_confirm_wrapper(request, uidb36=None, token=None): """ A wrapper around django.contrib.auth.views.password_reset_confirm. Needed because we want to set the user as active at this step. We also optionally do some additional password policy checks. """ # convert old-style base36-encoded user id to base64 uidb64 = uidb36_to_uidb64(uidb36) platform_name = { "platform_name": configuration_helpers.get_value('platform_name', settings.PLATFORM_NAME) } try: uid_int = base36_to_int(uidb36) user = User.objects.get(id=uid_int) except (ValueError, User.DoesNotExist): # if there's any error getting a user, just let django's # password_reset_confirm function handle it. return password_reset_confirm(request, uidb64=uidb64, token=token, extra_context=platform_name) if UserRetirementRequest.has_user_requested_retirement(user): # Refuse to reset the password of any user that has requested retirement. context = { 'validlink': True, 'form': None, 'title': _('Password reset unsuccessful'), 'err_msg': _('Error in resetting your password.'), } context.update(platform_name) return TemplateResponse(request, 'registration/password_reset_confirm.html', context) if waffle().is_enabled(PREVENT_AUTH_USER_WRITES): context = { 'validlink': False, 'form': None, 'title': _('Password reset unsuccessful'), 'err_msg': SYSTEM_MAINTENANCE_MSG, } context.update(platform_name) return TemplateResponse(request, 'registration/password_reset_confirm.html', context) if request.method == 'POST': password = request.POST['new_password1'] try: validate_password(password, user=user) except ValidationError as err: # We have a password reset attempt which violates some security # policy, or any other validation. Use the existing Django template to communicate that # back to the user. context = { 'validlink': True, 'form': None, 'title': _('Password reset unsuccessful'), 'err_msg': err.message, } context.update(platform_name) return TemplateResponse( request, 'registration/password_reset_confirm.html', context) # remember what the old password hash is before we call down old_password_hash = user.password response = password_reset_confirm(request, uidb64=uidb64, token=token, extra_context=platform_name) # If password reset was unsuccessful a template response is returned (status_code 200). # Check if form is invalid then show an error to the user. # Note if password reset was successful we get response redirect (status_code 302). if response.status_code == 200: form_valid = response.context_data['form'].is_valid( ) if response.context_data['form'] else False if not form_valid: log.warning( u'Unable to reset password for user [%s] because form is not valid. ' u'A possible cause is that the user had an invalid reset token', user.username, ) response.context_data['err_msg'] = _( 'Error in resetting your password. Please try again.') return response # get the updated user updated_user = User.objects.get(id=uid_int) # did the password hash change, if so record it in the PasswordHistory if updated_user.password != old_password_hash: entry = PasswordHistory() entry.create(updated_user) else: response = password_reset_confirm(request, uidb64=uidb64, token=token, extra_context=platform_name) response_was_successful = response.context_data.get('validlink') if response_was_successful and not user.is_active: user.is_active = True user.save() return response
def password_reset_confirm_wrapper(request, uidb36=None, token=None): """ A wrapper around django.contrib.auth.views.password_reset_confirm. Needed because we want to set the user as active at this step. We also optionally do some additional password policy checks. """ # convert old-style base36-encoded user id to base64 uidb64 = uidb36_to_uidb64(uidb36) platform_name = { "platform_name": configuration_helpers.get_value('platform_name', settings.PLATFORM_NAME) } # User can not get this link unless account recovery feature is enabled. if 'is_account_recovery' in request.GET and not is_secondary_email_feature_enabled(): raise Http404 try: uid_int = base36_to_int(uidb36) user = User.objects.get(id=uid_int) except (ValueError, User.DoesNotExist): # if there's any error getting a user, just let django's # password_reset_confirm function handle it. return password_reset_confirm( request, uidb64=uidb64, token=token, extra_context=platform_name ) if UserRetirementRequest.has_user_requested_retirement(user): # Refuse to reset the password of any user that has requested retirement. context = { 'validlink': True, 'form': None, 'title': _('Password reset unsuccessful'), 'err_msg': _('Error in resetting your password.'), } context.update(platform_name) return TemplateResponse( request, 'registration/password_reset_confirm.html', context ) if waffle().is_enabled(PREVENT_AUTH_USER_WRITES): context = { 'validlink': False, 'form': None, 'title': _('Password reset unsuccessful'), 'err_msg': SYSTEM_MAINTENANCE_MSG, } context.update(platform_name) return TemplateResponse( request, 'registration/password_reset_confirm.html', context ) if request.method == 'POST': # We have to make a copy of request.POST because it is a QueryDict object which is immutable until copied. # We have to use request.POST because the password_reset_confirm method takes in the request and a user's # password is set to the request.POST['new_password1'] field. We have to also normalize the new_password2 # field so it passes the equivalence check that new_password1 == new_password2 # In order to switch out of having to do this copy, we would want to move the normalize_password code into # a custom User model's set_password method to ensure it is always happening upon calling set_password. request.POST = request.POST.copy() request.POST['new_password1'] = normalize_password(request.POST['new_password1']) request.POST['new_password2'] = normalize_password(request.POST['new_password2']) password = request.POST['new_password1'] try: validate_password(password, user=user) except ValidationError as err: # We have a password reset attempt which violates some security # policy, or any other validation. Use the existing Django template to communicate that # back to the user. context = { 'validlink': True, 'form': None, 'title': _('Password reset unsuccessful'), 'err_msg': ' '.join(err.messages), } context.update(platform_name) return TemplateResponse( request, 'registration/password_reset_confirm.html', context ) # remember what the old password hash is before we call down old_password_hash = user.password if 'is_account_recovery' in request.GET: response = password_reset_confirm( request, uidb64=uidb64, token=token, extra_context=platform_name, template_name='registration/password_reset_confirm.html', post_reset_redirect='signin_user', ) else: response = password_reset_confirm( request, uidb64=uidb64, token=token, extra_context=platform_name ) # If password reset was unsuccessful a template response is returned (status_code 200). # Check if form is invalid then show an error to the user. # Note if password reset was successful we get response redirect (status_code 302). if response.status_code == 200: form_valid = response.context_data['form'].is_valid() if response.context_data['form'] else False if not form_valid: log.warning( u'Unable to reset password for user [%s] because form is not valid. ' u'A possible cause is that the user had an invalid reset token', user.username, ) response.context_data['err_msg'] = _('Error in resetting your password. Please try again.') return response # get the updated user updated_user = User.objects.get(id=uid_int) if 'is_account_recovery' in request.GET: try: updated_user.email = updated_user.account_recovery.secondary_email updated_user.account_recovery.delete() # emit an event that the user changed their secondary email to the primary email tracker.emit( SETTING_CHANGE_INITIATED, { "setting": "email", "old": user.email, "new": updated_user.email, "user_id": updated_user.id, } ) except ObjectDoesNotExist: log.error( 'Account recovery process initiated without AccountRecovery instance for user {username}'.format( username=updated_user.username ) ) updated_user.save() if response.status_code == 302 and 'is_account_recovery' in request.GET: messages.success( request, HTML(_( '{html_start}Password Creation Complete{html_end}' 'Your password has been created. {bold_start}{email}{bold_end} is now your primary login email.' )).format( support_url=configuration_helpers.get_value('SUPPORT_SITE_LINK', settings.SUPPORT_SITE_LINK), html_start=HTML('<p class="message-title">'), html_end=HTML('</p>'), bold_start=HTML('<b>'), bold_end=HTML('</b>'), email=updated_user.email, ), extra_tags='account-recovery aa-icon submission-success' ) else: response = password_reset_confirm( request, uidb64=uidb64, token=token, extra_context=platform_name ) response_was_successful = response.context_data.get('validlink') if response_was_successful and not user.is_active: user.is_active = True user.save() return response
def clean_password(self): """Enforce password policies (if applicable)""" password = self.cleaned_data["password"] if self.enforce_password_policy: validate_password(password, username=self.cleaned_data.get('username')) return password
def password_reset_logistration(request, **kwargs): """Reset learner password using passed token and new credentials""" reset_status = False uidb36 = kwargs.get('uidb36') token = kwargs.get('token') has_required_values, uid_int = _check_token_has_required_values( uidb36, token) if not has_required_values: AUDIT_LOG.exception("Invalid password reset confirm token") return JsonResponse({'reset_status': reset_status}) request.POST = request.POST.copy() request.POST['new_password1'] = normalize_password( request.POST['new_password1']) request.POST['new_password2'] = normalize_password( request.POST['new_password2']) password = request.POST['new_password1'] try: user = User.objects.get(id=uid_int) if not default_token_generator.check_token(user, token): AUDIT_LOG.exception("Token validation failed") return JsonResponse({'reset_status': reset_status}) validate_password(password, user=user) form = SetPasswordForm(user, request.POST) if form.is_valid(): form.save() reset_status = True if 'is_account_recovery' in request.GET: try: old_primary_email = user.email user.email = user.account_recovery.secondary_email user.account_recovery.delete() # emit an event that the user changed their secondary email to the primary email tracker.emit( SETTING_CHANGE_INITIATED, { "setting": "email", "old": old_primary_email, "new": user.email, "user_id": user.id, }) user.save() send_password_reset_success_email(user, request) except ObjectDoesNotExist: log.error( 'Account recovery process initiated without AccountRecovery instance for user {username}' .format(username=user.username)) except ValidationError as err: AUDIT_LOG.exception("Password validation failed") error_status = { 'reset_status': reset_status, 'err_msg': ' '.join(err.messages) } return JsonResponse(error_status) except Exception: # pylint: disable=broad-except AUDIT_LOG.exception("Setting new password failed") return JsonResponse({'reset_status': reset_status})
def password_reset_confirm_wrapper(request, uidb36=None, token=None): """ A wrapper around django.contrib.auth.views.password_reset_confirm. Needed because we want to set the user as active at this step. We also optionally do some additional password policy checks. """ # convert old-style base36-encoded user id to base64 uidb64 = uidb36_to_uidb64(uidb36) platform_name = { "platform_name": configuration_helpers.get_value('platform_name', settings.PLATFORM_NAME) } try: uid_int = base36_to_int(uidb36) user = User.objects.get(id=uid_int) except (ValueError, User.DoesNotExist): # if there's any error getting a user, just let django's # password_reset_confirm function handle it. return password_reset_confirm( request, uidb64=uidb64, token=token, extra_context=platform_name ) if UserRetirementRequest.has_user_requested_retirement(user): # Refuse to reset the password of any user that has requested retirement. context = { 'validlink': True, 'form': None, 'title': _('Password reset unsuccessful'), 'err_msg': _('Error in resetting your password.'), } context.update(platform_name) return TemplateResponse( request, 'registration/password_reset_confirm.html', context ) if waffle().is_enabled(PREVENT_AUTH_USER_WRITES): context = { 'validlink': False, 'form': None, 'title': _('Password reset unsuccessful'), 'err_msg': SYSTEM_MAINTENANCE_MSG, } context.update(platform_name) return TemplateResponse( request, 'registration/password_reset_confirm.html', context ) if request.method == 'POST': password = request.POST['new_password1'] try: validate_password(password, user=user) except ValidationError as err: # We have a password reset attempt which violates some security # policy, or any other validation. Use the existing Django template to communicate that # back to the user. context = { 'validlink': True, 'form': None, 'title': _('Password reset unsuccessful'), 'err_msg': err.message, } context.update(platform_name) return TemplateResponse( request, 'registration/password_reset_confirm.html', context ) # remember what the old password hash is before we call down old_password_hash = user.password response = password_reset_confirm( request, uidb64=uidb64, token=token, extra_context=platform_name ) # If password reset was unsuccessful a template response is returned (status_code 200). # Check if form is invalid then show an error to the user. # Note if password reset was successful we get response redirect (status_code 302). if response.status_code == 200: form_valid = response.context_data['form'].is_valid() if response.context_data['form'] else False if not form_valid: log.warning( u'Unable to reset password for user [%s] because form is not valid. ' u'A possible cause is that the user had an invalid reset token', user.username, ) response.context_data['err_msg'] = _('Error in resetting your password. Please try again.') return response # get the updated user updated_user = User.objects.get(id=uid_int) # did the password hash change, if so record it in the PasswordHistory if updated_user.password != old_password_hash: entry = PasswordHistory() entry.create(updated_user) else: response = password_reset_confirm( request, uidb64=uidb64, token=token, extra_context=platform_name ) response_was_successful = response.context_data.get('validlink') if response_was_successful and not user.is_active: user.is_active = True user.save() return response
def password_reset_confirm_wrapper(request, uidb36=None, token=None): """ A wrapper around django.contrib.auth.views.password_reset_confirm. Needed because we want to set the user as active at this step. We also optionally do some additional password policy checks. """ # convert old-style base36-encoded user id to base64 uidb64 = uidb36_to_uidb64(uidb36) platform_name = { "platform_name": configuration_helpers.get_value('platform_name', settings.PLATFORM_NAME) } # User can not get this link unless account recovery feature is enabled. if 'is_account_recovery' in request.GET and not is_secondary_email_feature_enabled(): raise Http404 try: uid_int = base36_to_int(uidb36) user = User.objects.get(id=uid_int) except (ValueError, User.DoesNotExist): # if there's any error getting a user, just let django's # password_reset_confirm function handle it. return password_reset_confirm( request, uidb64=uidb64, token=token, extra_context=platform_name ) if UserRetirementRequest.has_user_requested_retirement(user): # Refuse to reset the password of any user that has requested retirement. context = { 'validlink': True, 'form': None, 'title': _('Password reset unsuccessful'), 'err_msg': _('Error in resetting your password.'), } context.update(platform_name) return TemplateResponse( request, 'registration/password_reset_confirm.html', context ) if waffle().is_enabled(PREVENT_AUTH_USER_WRITES): context = { 'validlink': False, 'form': None, 'title': _('Password reset unsuccessful'), 'err_msg': SYSTEM_MAINTENANCE_MSG, } context.update(platform_name) return TemplateResponse( request, 'registration/password_reset_confirm.html', context ) if request.method == 'POST': # We have to make a copy of request.POST because it is a QueryDict object which is immutable until copied. # We have to use request.POST because the password_reset_confirm method takes in the request and a user's # password is set to the request.POST['new_password1'] field. We have to also normalize the new_password2 # field so it passes the equivalence check that new_password1 == new_password2 # In order to switch out of having to do this copy, we would want to move the normalize_password code into # a custom User model's set_password method to ensure it is always happening upon calling set_password. request.POST = request.POST.copy() request.POST['new_password1'] = normalize_password(request.POST['new_password1']) request.POST['new_password2'] = normalize_password(request.POST['new_password2']) password = request.POST['new_password1'] try: validate_password(password, user=user) except ValidationError as err: # We have a password reset attempt which violates some security # policy, or any other validation. Use the existing Django template to communicate that # back to the user. context = { 'validlink': True, 'form': None, 'title': _('Password reset unsuccessful'), 'err_msg': ' '.join(err.messages), } context.update(platform_name) return TemplateResponse( request, 'registration/password_reset_confirm.html', context ) # remember what the old password hash is before we call down old_password_hash = user.password if 'is_account_recovery' in request.GET: response = password_reset_confirm( request, uidb64=uidb64, token=token, extra_context=platform_name, template_name='registration/password_reset_confirm.html', post_reset_redirect='signin_user', ) else: response = password_reset_confirm( request, uidb64=uidb64, token=token, extra_context=platform_name ) # If password reset was unsuccessful a template response is returned (status_code 200). # Check if form is invalid then show an error to the user. # Note if password reset was successful we get response redirect (status_code 302). if response.status_code == 200: form_valid = response.context_data['form'].is_valid() if response.context_data['form'] else False if not form_valid: log.warning( u'Unable to reset password for user [%s] because form is not valid. ' u'A possible cause is that the user had an invalid reset token', user.username, ) response.context_data['err_msg'] = _('Error in resetting your password. Please try again.') return response # get the updated user updated_user = User.objects.get(id=uid_int) if 'is_account_recovery' in request.GET: try: updated_user.email = updated_user.account_recovery.secondary_email updated_user.account_recovery.delete() # emit an event that the user changed their secondary email to the primary email tracker.emit( SETTING_CHANGE_INITIATED, { "setting": "email", "old": user.email, "new": updated_user.email, "user_id": updated_user.id, } ) except ObjectDoesNotExist: log.error( 'Account recovery process initiated without AccountRecovery instance for user {username}'.format( username=updated_user.username ) ) updated_user.save() if response.status_code == 302 and 'is_account_recovery' in request.GET: messages.success( request, HTML(_( '{html_start}Password Creation Complete{html_end}' 'Your password has been created. {bold_start}{email}{bold_end} is now your primary login email.' )).format( support_url=configuration_helpers.get_value('SUPPORT_SITE_LINK', settings.SUPPORT_SITE_LINK), html_start=HTML('<p class="message-title">'), html_end=HTML('</p>'), bold_start=HTML('<b>'), bold_end=HTML('</b>'), email=updated_user.email, ), extra_tags='account-recovery aa-icon submission-success' ) else: response = password_reset_confirm( request, uidb64=uidb64, token=token, extra_context=platform_name ) response_was_successful = response.context_data.get('validlink') if response_was_successful and not user.is_active: user.is_active = True user.save() return response