orcasgit / django-fernet-fields

Fernet symmetric encryption for Django model fields
BSD 3-Clause "New" or "Revised" License
193 stars 81 forks source link

EncryptedEmailField() Not Compatible With Allauth Custom User Model #24

Open 9mido opened 4 years ago

9mido commented 4 years ago

This github project's EncryptedEmailField() is not compatible with allauth for encrypting an email during the allauth custom user model sign up process from my website's form. When I create a user from the command line or admin, this github project works perfectly. But when trying to create a user from the allauth sign up form, it gives me this error message:

Error:

django.core.exceptions.FieldError: EncryptedEmailField 'iexact' does not support lookups

I have the following custom user model:

from fernet_fields import EncryptedEmailField

class CustomUserManager(BaseUserManager):
    def _create_user(self, email, password,is_staff, is_superuser, **extra_fields):
        now = timezone.now()
        if not email:
            raise ValueError('The given email must be set')
        email = self.normalize_email(email)
        user = self.model(email=email,is_staff=is_staff, is_active=True,is_superuser=is_superuser, last_login=now,**extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user
    def create_user(self, email, password=None, **extra_fields):
        return self._create_user(email, password, False, False,**extra_fields)
    def create_superuser(self, email, password, **extra_fields):
        return self._create_user(email, password, True, True,**extra_fields)

class CustomUser(AbstractBaseUser, PermissionsMixin):
    objects = CustomUserManager()
    email = EncryptedEmailField()
    identifier = models.CharField(unique=True, max_length=50, default=uuid.uuid1)
    username = models.CharField(_('username'), max_length=30, blank=True, default='', unique=True)
    USERNAME_FIELD = 'username'
    first_name = models.CharField(_('first name'), max_length=30, blank=True)
    last_name = models.CharField(_('last name'), max_length=30, blank=True)
    is_staff = models.BooleanField(_('staff status'), default=False,
        help_text=_('Designates whether the user can log into this admin '
                    'site.'))
    is_mod = models.BooleanField(_('moderator status'), default=False,
        help_text=_('Designates whether the user can access mod pages and do mod things.'))
    is_active = models.BooleanField(_('active'), default=True,
        help_text=_('Designates whether this user should be treated as '
                    'active. Unselect this instead of deleting accounts.'))
    EMAIL_FIELD = 'email'
    REQUIRED_FIELDS = ['email']

Allauth files interfering with this:

https://github.com/pennersr/django-allauth/blob/master/allauth/utils.py#L145

https://github.com/pennersr/django-allauth/blob/master/allauth/account/forms.py#L336

https://github.com/pennersr/django-allauth/blob/master/allauth/account/adapter.py#L300

The main reason I want to do this is to protect myself from PII violations. Since allauth is probably the most popular django authentication package, I think this should be a required fix.

More details:

https://www.reddit.com/r/djangolearning/comments/fm7cnt/custom_user_model_encrypt_email/

I also created this same issue on the allauth github project page.

Sult commented 10 months ago

The reason this doesnt work (and wont be fixable) is that allauth requires to query the email field for lookups. You cannot query an encrypted field. Nor index it.

btw, under GDPR you dont have to encrypt email data.