8000 Add _legacy_get_session_auth_hash to fix Django 3.1 support by codingjoe · Pull Request #18 · codingjoe/django-mail-auth · GitHub
[go: up one dir, main page]

Skip to content

Add _legacy_get_session_auth_hash to fix Django 3.1 support #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 12, 2020
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
33 changes: 27 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-python@v1.1.1
- uses: actions/checkout@v2.0.0
- uses: actions/setup-python@v2
- uses: actions/checkout@v2
- run: python -m pip install -r requirements.txt
- run: python setup.py develop
- run: python setup.py build_sphinx -W
Expand All @@ -18,16 +18,37 @@ jobs:
python-version: [3.6, 3.7, 3.8]
steps:
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1.1.1
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- uses: actions/checkout@v2.0.0
- uses: actions/checkout@v2
- run: python setup.py test
- name: Codecov
run: |
python -m pip install codecov
codecov -t ${{secrets.CODECOV_TOKEN}}

extras:
needs: [docs]
runs-on: ubuntu-latest
strategy:
matrix:
extras:
- wagtail
python-version: [3.8]
steps:
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- uses: actions/checkout@v2
- run: python -m pip install -e ".[${{ matrix.extras }}]"
- run: python setup.py test
- name: Codecov
run: |
python -m pip install codecov
codecov -t ${{ secrets.CODECOV_TOKEN }}


PostgreSQL:
needs: [docs]
Expand All @@ -50,10 +71,10 @@ jobs:
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1.1.1
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- uses: actions/checkout@v2.0.0
- uses: actions/checkout@v2
- run: python -m pip install psycopg2-binary Django==${{ matrix.django-version }}
- run: python setup.py test
env:
Expand Down
2 changes: 1 addition & 1 deletion mailauth/contrib/admin/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _

from mailauth.views import LoginView

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Generated by Django 2.2.1 on 2019-05-27 10:39

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

import mailauth


class Migration(migrations.Migration):

Expand All @@ -14,6 +15,6 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='emailuser',
name='session_salt',
field=models.CharField(default=django.utils.crypto.get_random_string, editable=False, max_length=12),
field=models.CharField(default=mailauth.contrib.user.models._get_session_salt, editable=False, max_length=12),
),
]
21 changes: 21 additions & 0 deletions mailauth/contrib/user/migrations/0004_auto_20200812_0722.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 3.1 on 2020-08-12 07:22

import django
from django.db import migrations, models

import mailauth.contrib.user.models


class Migration(migrations.Migration):

dependencies = [
('mailauth_user', '0003_ci_unique_index'),
]

operations = [
migrations.AlterField(
model_name='emailuser',
name='first_name',
field=models.CharField(blank=True, max_length=150, verbose_name='first name'),
),
]
26 changes: 24 additions & 2 deletions mailauth/contrib/user/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.conf import settings
from django.contrib.auth.base_user import BaseUserManager
from django.contrib.auth.models import AbstractUser
from django.db import models
Expand Down Expand Up @@ -37,6 +38,10 @@ def create_superuser(self, email, **extra_fields):
return self._create_user(email, **extra_fields)


def _get_session_salt():
return get_random_string(12)


class AbstractEmailUser(AbstractUser):
EMAIL_FIELD = 'email'
USERNAME_FIELD = 'email'
Expand All @@ -51,7 +56,7 @@ class AbstractEmailUser(AbstractUser):
# Salt for the session hash replacing the password in this function.
session_salt = models.CharField(
max_length=12, editable=False,
default=get_random_string,
default=_get_session_salt,
)

def has_usable_password(self):
Expand All @@ -62,12 +67,29 @@ def has_usable_password(self):
class Meta(AbstractUser.Meta):
abstract = True

def _legacy_get_session_auth_hash(self):
# RemovedInDjango40Warning: pre-Django 3.1 hashes will be invalid.
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, algorithm='sha1').hexdigest()

def get_session_auth_hash(self):
"""Return an HMAC of the :attr:`.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()
algorithm = getattr(settings, 'DEFAULT_HASHING_ALGORITHM', None)
if algorithm is None:
return salted_hmac(key_salt, self.session_salt).hexdigest()
return salted_hmac(
key_salt,
self.session_salt,
# RemovedInDjango40Warning: when the deprecation ends, replace
# with:
# algorithm='sha256',
algorithm=algorithm,
).hexdigest()


delattr(AbstractEmailUser, 'password')
Expand Down
1 change: 0 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ tests_require =
pytest
pytest-django
pytest-cov
wagtail

[options.package_data]
* = *.txt, *.rst, *.html, *.po
Expand Down
5 changes: 4 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import django
import pytest
from django.contrib.auth import get_user_model
from django.utils import timezone
Expand Down Expand Up @@ -36,7 +37,9 @@ def admin_user(db):
@pytest.fixture()
def signature():
"""Return a signature matching the user fixture."""
return 'LZ.173QUS.1Hjptg.lf2hFgOXQtjQsFypS2ItRG2hkpA'
if django.VERSION < (3, 1):
return 'LZ.173QUS.1Hjptg.lf2hFgOXQtjQsFypS2ItRG2hkpA'
return 'LZ.173QUS.1Hjptg.UtFdkTPoyrSA0IB6AUEhtz_hMyFZY0kcREE1HnWdFq4'


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

Expand Down Expand Up @@ -28,6 +29,32 @@ def test_get_session_auth_hash__unique(self, db):

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

@pytest.mark.skipif(django.VERSION < (3, 1), reason="requires Django 3.1 or higher")
def test_legacy_get_session_auth_hash__default(self, db):
user = EmailUser(email='spiderman@avengers.com')

assert user.session_salt
assert user._legacy_get_session_auth_hash()

@pytest.mark.skipif(django.VERSION < (3, 1), reason="requires Django 3.1 or higher")
def test_legacy_get_session_auth_hash__value_error(self, db):
user = EmailUser(email='spiderman@avengers.com', session_salt=None)

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

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

@pytest.mark.skipif(django.VERSION < (3, 1), reason="requires Django 3.1 or higher")
def test_legacy_get_session_auth_hash__unique(self, db):
spiderman = EmailUser(email='spiderman@avengers.com')
ironman = EmailUser(email='ironman@avengers.com')

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

def test_password_field(self):
user = EmailUser(email='spiderman@avengers.com')
with pytest.raises(FieldDoesNotExist):
Expand Down
7 changes: 6 additions & 1 deletion tests/contrib/wagtail/test_views.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
from mailauth.contrib.wagtail.views import LoginView
import pytest

from mailauth.forms import EmailLoginForm


class TestLoginView:
def test_get_from_class(self):
pytest.importorskip('wagtail')
from mailauth.contrib.wagtail.views import LoginView
assert issubclass(LoginView().get_form_class(), EmailLoginForm)

def test_form_valid(self, rf, db):
pytest.importorskip('wagtail')
from mailauth.contrib.wagtail.views import LoginView
view = LoginView()
request = rf.get('/')

Expand Down
2 changes: 1 addition & 1 deletion tests/test_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,5 @@ def test_get_login_url(self, signer, signature):
backend = MailAuthBackend()
MailAuthBackend.signer = signer
assert backend.get_login_url(signature) == (
"/accounts/login/LZ.173QUS.1Hjptg.lf2hFgOXQtjQsFypS2ItRG2hkpA"
f"/accounts/login/{signature}"
)
11 changes: 11 additions & 0 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,20 @@

from mailauth.contrib.user import models

try:
import psycopg2
except ImportError:
psycopg2 = None


postgres_only = pytest.mark.skipif(
psycopg2 is None, reason="at least mymodule-1.1 required"
)


class TestEmailUser:

@postgres_only
def test_email__ci_unique(self, db):
models.EmailUser.objects.create_user('IronMan@avengers.com')
with pytest.raises(IntegrityError):
Expand Down
17 changes: 13 additions & 4 deletions tests/testapp/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,21 @@
'mailauth',
'mailauth.contrib.admin',
'mailauth.contrib.user',
'mailauth.contrib.wagtail',
'wagtail.admin',
'wagtail.core',
'wagtail',

]

try:
import wagtail # NoQA
except ImportError:
pass
else:
INSTALLED_APPS += [
'mailauth.contrib.wagtail',
'wagtail.admin',
'wagtail.core',
'wagtail',
]

AUTHENTICATION_BACKENDS = (
'mailauth.backends.MailAuthBackend',
)
Expand Down
13 changes: 10 additions & 3 deletions tests/testapp/urls.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
from django.contrib import admin
from django.urls import include, path
from wagtail.admin import urls as wagtailadmin_urls

urlpatterns = [
path('accounts/', include('mailauth.urls')),
path("", include("mailauth.contrib.wagtail.urls")),
path("django-admin/", admin.site.urls),
path("admin/", include(wagtailadmin_urls)),

]

try:
from wagtail.admin import urls as wagtailadmin_urls
except ImportError:
pass
else:
urlpatterns += [
path("", include("mailauth.contrib.wagtail.urls")),
path("admin/", include(wagtailadmin_urls)),
]
0