Legacy Password Field

Is there any way to use the password field from my legacy DB to authenticate? I have implemented the custom user model as documented and and using USERNAME_FIELD = ‘email’ to authenticate with email. The createsuperuser function DOES prompt for email but errors without prompting for password with the below error.

django.db.utils.ProgrammingError: column accounts_users.password does not exist
LINE 1: SELECT “accounts_users”.“id”, “accounts_users”.“password”, "…

Edit: Custom User Model

class CardsUserManager(BaseUserManager):
    
    def create_user(self, email, password, is_active=True, is_staff=False, is_superuser=False):
        if not email:
            raise ValueError("Users must have and email address!")
        if not password:
            raise ValueError("Users must have a password!")
        user_obj = self.model(
            email = self.normalize_email(email)
        )
        user_obj.set_password(password) # Change user password
        username_extract   = email_split(email)
        user.obj.username  = username_extract.local
        user_obj.active    = is_active
        user_obj.staff     = is_staff
        user_obj.superuser = is_superuser
        user_obj.save(self._db)
        return user_obj

    def create_staffuser(self, email, password=None):
        user = self.create_user(
            email,
            password = password,
            is_staff = True
        )
        return user

    def create_superuser(self, email, password=None):
        user = self.create_user(
            email,
            password = password,
            is_staff = True,
            is_superuser = True
        )
        return user

class Users(AbstractBaseUser):

        name               = models.CharField(max_length=255)
        email              = models.CharField(unique=True, max_length=255)
        group              = models.ForeignKey('app.Groups', models.DO_NOTHING)
        phone              = models.CharField(max_length=255, blank=True, null=True)
        address            = models.CharField(max_length=255, blank=True, null=True)
        title              = models.CharField(max_length=255, blank=True, null=True)
        fax                = models.CharField(max_length=255, blank=True, null=True)
        created_at         = models.DateTimeField(blank=True, null=True)
        updated_at         = models.DateTimeField(blank=True, null=True)
        login              = models.CharField(unique=True, max_length=255)
        crypted_password   = models.CharField(max_length=255)
        password_salt      = models.CharField(max_length=255)
        persistence_token  = models.CharField(max_length=255)
        login_count        = models.IntegerField()
        failed_login_count = models.IntegerField()
        last_request_at    = models.DateTimeField(blank=True, null=True)
        current_login_at   = models.DateTimeField(blank=True, null=True)
        last_login         = models.DateTimeField(blank=True, null=True)
        current_login_ip   = models.CharField(max_length=255, blank=True, null=True)
        last_login_ip      = models.CharField(max_length=255, blank=True, null=True)
        time_zone          = models.CharField(max_length=255)
        preferences        = models.TextField(blank=True, null=True)
        perishable_token   = models.CharField(max_length=255)

        USERNAME_FIELD     = 'email'
        PASSWORD_FIELD     = 'crypted_password'

        # ## Runs all requests through custom user manager
        objects = CardsUserManager()

        REQUIRED_FIELDS = []

        def __str__(self):
            return self

        def get_full_name(self):
            return self.email

        def get_short_name(self):
            return self.email

        def has_perm(self, perm, obj=None):
            "Does the user have a specific permission?"
            # Simplest possible answer: Yes, always
            return True

        def has_module_perms(self, app_label):
            "Does the user have permissions to view the app `app_label`?"
            # Simplest possible answer: Yes, always
            return True

        @property
        def is_staff(self):
            return self.is_staff

        @property
        def is_superuser(self):
            return self.is_superuser

        @property
        def is_active(self):
            return self.is_active

can you post your custom user model, please?

Posted. I am working of the formatting…

Do you know how the password is stored in that database?

If it’s stored in plain text (which is a very Bad Thing™), then it would be trivial to do this.

If the password is encrypted, then you need an implementation of the encryption algorithm that will convert the submitted password to the same encrypted value as what’s stored in the database. This is a lot easier if the legacy system used Python and provided a Python-based function for doing this.

It’s also possible if the legacy system exposed some type of API where you could use it to validate the credentials. How practical this may be again depends upon how the legacy system was constructed.

Using any of these methods will still require that you provide a password field if you are going to use the createsuperuser command to populate your table. That field is always requested as shown in the Note for REQUIRED_FIELDS. You don’t need to use it for your authentication process, but that command requires it.
You could avoid that requirement by writing your own createsuperuser command.

Ken

When posting code, enclose it between lines consisting of only three backtick - ` characters. This means you would have one line of ```, followed by your code, followed by another line of ```.

Ken,
The legacy system was ruby based, I have implemented a hasher that I hope to work but don think I am getting that far. It is SAH512 for reference. Referencing that note you mentioned for REQUIRED_FIELDS is specifics ‘password’, does that mean that I need change my current ‘crypted_password’ field name to be just ‘password’?

Again, this is a requirement of the createsuperuser command, not of Django or for the User object.

If you are going to use the system-provided createsuperuser command interactively, you must have a field named password. Whether you use that password field anywhere else is up to you.

I updated my original post to include my user manager class and sub classes. I understand that the createsuperuser command needs the ‘password’ field in the DB. I don’t think I understand why it is not prompting when I run it. Additionally, I can not log in with an established super user. I get the “Please enter the correct email and password for a staff account.” message at the login page. To me this all means that my authentication is not looking at the right password field. Am I still missing something or am I just dumb? lol

I’m thinking you might be confusing the “createsuperuser” command with the authentication process.

They’re really not related all that closely.

The createsuperuser command won’t ask for a password field if it doesn’t exist in the model.
However, the default UserManager - and I can now also see in your custom manager, both have a call to the set_password method of the user object. (I don’t remember seeing the CardsUserManager in your original post.) You’re explicitly attempting to set the value of a field that doesn’t exist.

(Breaking this down into two responses…)

(Response part 2 - divided into two parts to emphasize that these are two completely separate and unrelated issues.)

This is an issue of how you’re performing authentication. That would be part of the view being presented to allow a user to log in. We’d need to see that view to verify you’re handling the login process correctly. This is especially true if you’re using a non-standard encryption method for password storage and / or a non-standard password field.

I am using the standard admin login view.

hasher: ‘app.hashers.PBKDF2SHA512PasswordHasher’,

app.hashers.py

import hashlib
from django.contrib.auth.hashers import PBKDF2PasswordHasher

class PBKDF2SHA512PasswordHasher(PBKDF2PasswordHasher):
    algorithm = "pbkdf2_sha512"
    digest = hashlib.sha512

If you’re using your custom user class with a non-standard named password field, you’re going to need to write your own authenticator. Django isn’t going to know that it needs to check the password to a non-standard field. See Customizing authentication in Django.

Also, have you verified that you can hash a known password and have it match the passwords that were stored in the Ruby system?

Ken,
This is my next step, I wanted to make sure there wasn’t a work around I was not aware of. I am going to start building my own authenticator. The ruby system used SHA512 with salt. Django doesn’t handle SHA512 that I could find, so I will likely need to create a hasher as well if the above (found on google), doesn’t work.