Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Users in initial data fixture

I'm creating a few users by default in my fixtures/initial_data.json so as to have some testing "subjects." The problem I'm experiencing is password generation. I could set the password in the 'fields', but that won't generate a hashed password:

[
    { "model": "auth.user",
        "pk": 1,
        "fields": {
            "username": "user1",
            "password": "password"
        }
    }
]

I need a way to generate the user's password. Do I have to do this manually and generate a string like {hash_method}${salt}${hashed_password} like Django does?

like image 957
Naftuli Kay Avatar asked Nov 05 '11 00:11

Naftuli Kay


People also ask

How to load initial data in Django?

You can load data by calling manage.py loaddata <fixturename> , where <fixturename> is the name of the fixture file you've created. Each time you run loaddata , the data will be read from the fixture and reloaded into the database.

How do I load all fixtures in Django?

By default, Django only loads fixtures into the default database. Use before_scenario to load the fixtures in all of the databases you have configured if your tests rely on the fixtures being loaded in all of them.


3 Answers

What might be easier in this case (and if you only need a few users) is to create some fake user accounts through the admin (including passwords) and then dump the users to a fixtures file using dumpdata:

$ python manage.py dumpdata auth.User --indent 4 > users.json

which will automatically create the fixtures for you and can be used later with loaddata

(You could just create one fake account and use the hash in the rest of your fixtures if you needed lots of test users)

https://docs.djangoproject.com/en/dev/ref/django-admin/#dumpdata-appname-appname-appname-model

like image 75
Timmy O'Mahony Avatar answered Nov 02 '22 02:11

Timmy O'Mahony


OK, I agree with the answers, but let me answer the original questions.

How to get the password "as Django would have hashed it"?

Let's look a the file django/contrib/auth/hashers.py:

def make_password(password, salt=None, hasher='default'):
    """
    Turn a plain-text password into a hash for database storage

    Same as encode() but generates a new random salt.  If
    password is None or blank then UNUSABLE_PASSWORD will be
    returned which disallows logins.
    """
    # ...

See this example session:

./manage.py shell

>>> from django.contrib.auth.hashers import make_password, HASHERS
>>> make_password('test')
'pbkdf2_sha256$10000$vkRy7QauoLLj$ry+3xm3YX+YrSXbri8s3EcXDIrx5ceM+xQjtpLdw2oE='

# fix salt:
>>> make_password('test', 'abc')
'pbkdf2_sha256$10000$abc$MqJS5OAgSmf9SD9mfoY8fgLo8sSKmEcef0AjjMp1Q7w='

# use different (maybe faster, maybe unsafe!) hasher

In [12]: HASHERS
Out[12]:
{'bcrypt': <django.contrib.auth.hashers.BCryptPasswordHasher object at 0x29c6d50>,
 'crypt': <django.contrib.auth.hashers.CryptPasswordHasher object at 0x29c6f50>,
 'md5': <django.contrib.auth.hashers.MD5PasswordHasher object at 0x29c6e10>,
 'pbkdf2_sha1': <django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher object at 0x29c6bd0>,
 'pbkdf2_sha256': <django.contrib.auth.hashers.PBKDF2PasswordHasher object at 0x29c6cd0>,
 'sha1': <django.contrib.auth.hashers.SHA1PasswordHasher object at 0x29c6dd0>,
 'unsalted_md5': <django.contrib.auth.hashers.UnsaltedMD5PasswordHasher object at 0x29c6ed0>,
 'unsalted_sha1': <django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher object at 0x29c6e50>}

In [14]: [make_password('test', hasher=name) for name in HASHERS]
Out[14]:
['sha1$LdKsAbJRjlVP$2eb2346387cc510f576f2f11eebdfe18b20d1be1',
 'pbkdf2_sha256$10000$Ck8gtWQJnJ9x$M/OqP548d5KcPqFuVRgXb84unjYbYDH6oyimbDndE3k=',
 'pbkdf2_sha1$10000$BJqRu5OwylVF$hUvMLIzBujt9kPbML/dei1vLiMQ=',
 'crypt$$d9grSeqDhMFek',
 '098f6bcd4621d373cade4e832627b4f6',
 'sha1$$a94a8fe5ccb19ba61c4c0873d391e987982fbbd3',
 'bcrypt$$2a$12$WlJP5zm2lmdJ4g/pSE1xF.d/8w.XRT5mo/vGlkKdglBtzcxKw7XJS',
 'md5$txHYmSYJKhD4$69286d4a1abd348fbddc9df7687e2ed4']

You can also manually use the hasher's encode method, but the above utility function has you covered in an easier way.

like image 23
Tomasz Gandor Avatar answered Nov 02 '22 02:11

Tomasz Gandor


I came across the same problem while writing fixtures for tests. Here's how I'm handling this in unit tests.

Creating data from admin and dumping them into fixture works but I don't quite like being dependent on manually doing it. So here's what I do -

Create the fixture just as you've done and then in the setUp method, set_passwords for the users.

user_fixture.json

[
    { "model": "auth.user",
        "pk": 1,
        "fields": {
            "username": "user1",
            "password": "password"
        }
    }
]

test_user.py

def setUp(self):
    self.User = get_user_model()

    # Fix the passwords of fixtures
    for user in self.User.objects.all():
        user.set_password(user.password)
        user.save()

This way I can cleanly write the passwords in fixture and refer back to them when I need to and create more fixtures simply by editing the fixture file.

like image 16
Gaurav Butola Avatar answered Nov 02 '22 02:11

Gaurav Butola