2

I apologize if there has been a substantial answer on this already, I have searched for quite a while and can't find any helpful answers.

I have a django project that has varying levels of account access. I have a group of 'Managers' and I want to allow them to manage user accounts.

I want the Managers to be able to create the user account objects for the users. However, I don't want them to have to deal with creating their passwords and sending them to the users (for obvious reasons). This way, managers can impersonate users to get work done on their behalf, and users maintain password control and ownership of their data.

The idea is that managers create the account, and when the account is created Users will be sent a password reset form (same as django's out-of-box auth) which will allow them to set their passwords.

My code looks similar to below (omitted non-imperative stuff)

from django.contrib.auth.models import User
from django.contrib.auth.forms import PasswordResetForm

@manager_required
def manager_add_users(request):
    add_user_form = manager_add_user_form(request.POST)
    new_user_name = add_user_form.cleaned_data['user_name']
    new_user_email = add_user_form.cleaned_data['user_email']

    new_user = User.objects.create_user(
        username = new_user_name, 
        email = new_user_email, 
        )
    new_user.save()

    set_password_form = PasswordResetForm({'email': new_user.email })
            if set_password_form.is_valid():
                print 'Reset Form Is Valid'
                set_password_form.save(
                    request= request,
                    use_https=True,
                    from_email="support@org.com",
                    email_template_name='registration/password_reset_email.html')

The account creates properly and everything runs without error. The issue is that although the form is valid (reset form is valid statement prints) it is not actually sending the reset form. There are no form errors.

However, in testing when I initialize the form with an address that already exists in the system like this:

set_password_form = PasswordResetForm({'email':'existing_address@example.com'})

The password reset form sends without error. So it only works with existing user email addresses in the system, but although the user has been created and the .save() method called, it's still not catching it (The users are marked as 'Active' upon creation, so they should be able to be found)

I'm a bit at a loss. I can think of a few ways that I could get around this issue, but this seems the most direct way of doing it and I'm really not entirely sure why it doesn't work.

Yes, I am able to send messages. I am using django's backend mail for testing:

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
rob
  • 2,119
  • 1
  • 22
  • 41
  • You haven't mentioned anything about your email backend. Django itself doesn't send any emails, you have to configure an email server. When running tests it substitutes a dummy backend. Have you set up an email server and confirmed that you can actually send emails with it? – Kevin Christopher Henry Jul 05 '16 at 23:32
  • Sorry. I'm using django's backend. I figured it would be clear that I had a mail server configured when I mentioned that I successfully have mails delivered in some test cases. I have updated the question to include my settings. – rob Jul 06 '16 at 00:56
  • Thanks for clarifying. I mentioned it because it's possible for tests to work just fine without having a mail server set up since Django's test runner substitutes a test backend. – Kevin Christopher Henry Jul 06 '16 at 03:35

1 Answers1

1

Glancing at the source code, it looks like Django is ignoring the request because the password is blank.

Try setting a temporary password (using, say, django.utils.crypto.get_random_string()) before saving the user.

Kevin Christopher Henry
  • 46,175
  • 7
  • 116
  • 102
  • Sending passwords with an email is a bad Idea. Use dango-registration to generate tokens and send the token instead. Once the token is clicked from the email read it and offer the user to set the password. – dmitryro Jul 06 '16 at 03:40
  • 1
    @dmitryro: What you're describing is exactly how Django's password reset flow works. My answer is about *setting* a temporary password in the database, not *sending* it in an email. – Kevin Christopher Henry Jul 06 '16 at 03:48
  • Thank you. This is the absolute correct answer. Although user accounts created without passwords were active and could be impersonated by admins, the lack of password prevented auth from sending a reset. It seems so obvious now! – rob Jul 06 '16 at 12:39