1

I have two types of Django servers. One is a central server that contains a master database. There's only one of these.

Then there's an arbitrary number of client servers that contain their own databases. These client databases act as a cache for the master database.

This is used for users. I a user tries to log in on client server 1, that server looks for the user in its database. If it's not there, it goes out to the central server and asks that server if the user exists in the master database. If so, the central server returns the users info so that the client server can store/cache it in its own database and then log the user in. Each successive time that user tries to log in, the user is found in the client database and it no longer has to go out to the central server.

The central server returns the users information as JSON like so:

{
    "username": "joe.bag.o.doughnuts",
    "id": 143,
    "password": "fksdfjfldskjf",
}

My issue here is the password. when I put the value in there as just user.password, it uses the encrypted version of that password. This is good because I don't want the plain text password out there in http connections for security reasons. However, how do I store the encrypted password correctly when creating a copy of the user on the client server? If I set password to the encrypted text (User.objects.create(username=<retrieved_username>, password=<retrieved_password_which_is_already_encrypted>)), it will treat it as a plain text password and will then encrypt it... even though it's already encrypted so it's encrypting the encryption, not the actual password.

Ian Kirkpatrick
  • 1,861
  • 14
  • 33

1 Answers1

0

I wonder if you can achieve this a different way than by way of User.objects.create(...)? Depends on the server constraints, etc. but would this work for you?

From bash, maybe as cron job, something like this:

python manage.py dumpdata auth.users --indent 2 --natural-foreign --output users.json

Then load onto the other server using something like this:

python manage.py loaddata users.json

Or in the alternative, you might be able to create a custom user manager for the importation of users with previously hashed passwords:

from django.contrib.auth.base_user import BaseUserManager

class UserManager(BaseUserManager):
    use_in_migrations = True

    def _create_user(self, email, password, **extra_fields):
        """
        Creates and saves a User with the given email and password.
        """
        if not email:
            raise ValueError('The given email must be set')
        email = self.normalize_email(email)
        user = self.model(email=email, password=password, **extra_fields)
        # Normally here Django uses the set_password function
        # https://docs.djangoproject.com/en/2.0/ref/contrib/auth/#django.contrib.auth.models.User.set_password
        user.save(using=self._db)
        return user

More info on extending/overriding User class here: https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html

Dylan
  • 282
  • 3
  • 11
  • The first one won't work because the servers are on separate computers. I can't just load the file cause it's not in the same file system. That's why I have two servers. The second one will still treat the password as a raw password that's not encrypted. That's the problem, is it's encrypted at the time I'm recreating the user. – Ian Kirkpatrick Feb 10 '18 at 18:50
  • 1) SCP, etc. no? I don't know the setup of your network. 2) You sure? When I look at my password export it has the algo/rounds embedded in the string: i.e. `pbkdf2_sha256$30000$hOfM...` Why wouldn't you be able to import that directly into a password field and have it work? e.g.: https://github.com/django/django/blob/master/django/contrib/auth/hashers.py – Dylan Feb 10 '18 at 19:39
  • You mean like de-encrypt it? I'v thought of that. I've never really worked with encryption so I wondered if there was an alternative way. I also feel that SCP would defeat the purpose of the server. Maybe I'll have to do that in the end but I'm searching for more official django-esque ways first. – Ian Kirkpatrick Feb 10 '18 at 20:14
  • No, no, just add the full hash string as the password for the User instance. I think that should work. – Dylan Feb 10 '18 at 23:11