Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions mailauth/contrib/user/migrations/0002_emailuser_session_salt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 2.2.1 on 2019-05-27 10:39

import django.utils.crypto
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('mailauth_user', '0001_initial'),
]

operations = [
migrations.AddField(
model_name='emailuser',
name='session_salt',
field=models.CharField(default=django.utils.crypto.get_random_string, editable=False, max_length=12),
),
]
15 changes: 15 additions & 0 deletions mailauth/contrib/user/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.contrib.auth.base_user import BaseUserManager
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils.crypto import get_random_string, salted_hmac
from django.utils.translation import ugettext_lazy as _


Expand Down Expand Up @@ -39,6 +40,10 @@ class AbstractEmailUser(AbstractUser):
email = models.EmailField(_('email address'), unique=True, db_index=True)
username = None
password = None
session_salt = models.CharField(
max_length=12, editable=False,
default=get_random_string,
)

def has_usable_password(self):
return False
Expand All @@ -48,6 +53,16 @@ def has_usable_password(self):
class Meta(AbstractUser.Meta):
abstract = True

def get_session_auth_hash(self):
"""Return an HMAC of the session_salt field."""
key_salt = "mailauth.contrib.user.models.EmailUserManager.get_session_auth_hash"
if not self.session_salt:
raise ValueError("'session_salt' must be set")
return salted_hmac(key_salt, self.session_salt).hexdigest()


delattr(AbstractEmailUser, 'password')


class EmailUser(AbstractEmailUser):
class Meta(AbstractEmailUser.Meta):
Expand Down
26 changes: 26 additions & 0 deletions tests/contrib/auth/test_models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pytest
from django.core.exceptions import FieldDoesNotExist

from mailauth.contrib.user.models import EmailUser

Expand All @@ -7,6 +8,31 @@ class TestAbstractEmailUser:
def test_has_usable_password(self):
assert not EmailUser().has_usable_password()

def test_get_session_auth_hash__default(self, db):
user = EmailUser(email='spiderman@avengers.com')

assert user.session_salt
assert user.get_session_auth_hash()

def test_get_session_auth_hash__value_error(self, db):
user = EmailUser(email='spiderman@avengers.com', session_salt=None)

with pytest.raises(ValueError) as e:
user.get_session_auth_hash()

assert "'session_salt' must be set" in str(e)

def test_get_session_auth_hash__unique(self, db):
spiderman = EmailUser(email='spiderman@avengers.com')
ironman = EmailUser(email='ironman@avengers.com')

assert spiderman.get_session_auth_hash() != ironman.get_session_auth_hash()

def test_password_field(self):
user = EmailUser(email='spiderman@avengers.com')
with pytest.raises(FieldDoesNotExist):
user.password


class TestEmailUserManager:

Expand Down