Home > Enterprise >  Django is hashing my passwords different when creating a User vs trying to authenticate a user
Django is hashing my passwords different when creating a User vs trying to authenticate a user

Time:04-27

I'm having trouble getting authentication to work and I found that the problem is my when I create a user their password is hashed in a different style than PBKDF2. Instead the passwords are always in a format like this: !iak7ijJTzsXRgsbwqtQBtXCZeU3Ccd96k2PpOCRa .

However, when I'm working in my views make_password and check_password are using PBKDF2.

Model:

class UserManager(BaseUserManager):
    def create_user(self, email, password):
        if not email:
            raise ValueError("User must have an email address")

        user = self.model(
            email = self.normalize_email(email),
        )

        user.set_password(password)
        user.save()
        return user

    def create_super_user(self, email, password=None):
        if not email:
            raise ValueError("User must have an email address")

        user = self.model(
            email = self.normalize_email(email),
        )

        user.is_admin = True
        user.save()
        return user

class User(AbstractBaseUser):
    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    
    email=models.EmailField(
        verbose_name='Email',
        max_length=255,
        unique=True
    )

    password=models.CharField(
        max_length=255, 
        verbose_name='password'
    )

    username = None
    first_name = None
    last_name = None

    is_active = models.BooleanField(default=True)

    EMAIL_FIELD = 'email'
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = UserManager()
    
    def __str__(self):
        return self.email

I suspect the issue is coming from my custom Model, but it's identical to one I wrote for another app that had no issues.

Register View:

class CreateUser(APIView):
    serializer_class = CreateUserSerializer
    def post(self, request, format='json'):
        serializer = self.serializer_class(data=request.data)

        if serializer.is_valid():
            email = serializer.data.get('email')
            password = serializer.data.get('password')

            userObj = User.objects.create_user(email=email, password=password)
            userObj.save()
            return Response(status=status.HTTP_201_CREATED)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Login View:

class LogIn(APIView):
    serializer_class = LogInSerializer
    authentication_classes = [SessionAuthentication, BasicAuthentication]

    def post(self, request, format='json'):
        serializer = self.serializer_class(data=request.data)

        if serializer.is_valid():
            email = serializer.data.get('email')
            password = serializer.data.get('password')

            tObj = User.objects.get(email=email)
            hashed_pwd = make_password("123456")
            print(hashed_pwd)
            print(tObj.password)

            print(tObj.check_password(password))
            

            user = authenticate(email=email, password=password)
            print(user)

            if user is not None:

CodePudding user response:

The ! at the start of the password value has a special meaning in Django - it means that an unusable password has been set for the user - the rest of the value is just a random string that will never be successfully validated.

So the question is why is an unusable password being set? There are two possibilities I can see from your code:

  1. UserManager.create_super_user doesn't set the user's password at all - if you are using this to create users, then no password will be set for them.

  2. If you're using the CreateUserSerializer, then it may be that the value of password is None - we would need to see the serializer definition to confirm whether a null value would be considered valid. I think this is the most likely issue. Passing None to create_user will cause set_password to set an unusable password. You then need to investigate why an empty value is being passed to the serializer.

CodePudding user response:

The problem was what solarissmoke proposed with the CreateUserSerializer. I had my password set to write only which wasn't letting my view to get to password, instead it was returning None.

I changed my view from this:

class CreateUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('email', 'password')
        extra_kwargs = {
            'password' : {'write_only': True}
        }

To this (corrected version):

class CreateUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('email', 'password')
  • Related