parent
dc16868fb4
commit
ce6610f47b
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 3.2.18 on 2023-06-01 15:42
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('authenticators', '0005_addroleaction'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='loginpasswordauthenticator',
|
||||
name='registration_open',
|
||||
field=models.BooleanField(
|
||||
default=True, help_text='Allow users to create accounts.', verbose_name='Registration open'
|
||||
),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 3.2.18 on 2023-06-01 15:44
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def migrate_registration_open(apps, schema_editor):
|
||||
LoginPasswordAuthenticator = apps.get_model('authenticators', 'LoginPasswordAuthenticator')
|
||||
authenticator = LoginPasswordAuthenticator.objects.get_or_create(
|
||||
slug='password-authenticator',
|
||||
defaults={'enabled': True},
|
||||
)[0]
|
||||
authenticator.registration_open = getattr(settings, 'REGISTRATION_OPEN', True)
|
||||
authenticator.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('authenticators', '0006_loginpasswordauthenticator_registration_open'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(migrate_registration_open, reverse_code=migrations.RunPython.noop),
|
||||
]
|
|
@ -278,6 +278,9 @@ class AddRoleAction(AuthenticatorRelatedObjectBase):
|
|||
|
||||
|
||||
class LoginPasswordAuthenticator(BaseAuthenticator):
|
||||
registration_open = models.BooleanField(
|
||||
_('Registration open'), default=True, help_text=_('Allow users to create accounts.')
|
||||
)
|
||||
remember_me = models.PositiveIntegerField(
|
||||
_('Remember me duration'),
|
||||
blank=True,
|
||||
|
|
|
@ -18,7 +18,6 @@ import copy
|
|||
import math
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import forms as auth_forms
|
||||
from django.forms.widgets import Media
|
||||
from django.utils import html
|
||||
|
@ -155,15 +154,13 @@ class AuthenticationForm(auth_forms.AuthenticationForm):
|
|||
invalid_login_message = [
|
||||
_('Incorrect %(username_label)s or password.') % {'username_label': username_label},
|
||||
]
|
||||
if app_settings.A2_USER_CAN_RESET_PASSWORD is not False and getattr(
|
||||
settings, 'REGISTRATION_OPEN', True
|
||||
):
|
||||
if app_settings.A2_USER_CAN_RESET_PASSWORD is not False and self.authenticator.registration_open:
|
||||
invalid_login_message.append(
|
||||
_('Try again, use the forgotten password link below, or create an account.')
|
||||
)
|
||||
elif app_settings.A2_USER_CAN_RESET_PASSWORD is not False:
|
||||
invalid_login_message.append(_('Try again or use the forgotten password link below.'))
|
||||
elif getattr(settings, 'REGISTRATION_OPEN', True):
|
||||
elif self.authenticator.registration_open:
|
||||
invalid_login_message.append(_('Try again or create an account.'))
|
||||
error_messages['invalid_login'] = ' '.join([force_str(x) for x in invalid_login_message])
|
||||
return error_messages
|
||||
|
|
|
@ -18,7 +18,6 @@ import logging
|
|||
from collections import OrderedDict
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import forms as auth_forms
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.exceptions import ValidationError
|
||||
|
@ -53,6 +52,7 @@ class PasswordResetForm(HoneypotForm):
|
|||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.authenticator = kwargs.pop('password_authenticator')
|
||||
super().__init__(*args, **kwargs)
|
||||
self.users = []
|
||||
if app_settings.A2_USER_CAN_RESET_PASSWORD_BY_USERNAME:
|
||||
|
@ -182,7 +182,7 @@ class PasswordResetForm(HoneypotForm):
|
|||
sms_sent = True
|
||||
if not email_sent and email:
|
||||
logger.info('password reset request for "%s", no user found', email)
|
||||
if getattr(settings, 'REGISTRATION_OPEN', True):
|
||||
if self.authenticator.registration_open:
|
||||
ctx = {
|
||||
'registration_url': utils_misc.make_url(
|
||||
'registration_register',
|
||||
|
|
|
@ -175,16 +175,22 @@ def get_backends():
|
|||
return backends
|
||||
|
||||
|
||||
def get_password_authenticator():
|
||||
from authentic2.apps.authenticators.models import LoginPasswordAuthenticator
|
||||
|
||||
return LoginPasswordAuthenticator.objects.get_or_create(
|
||||
slug='password-authenticator',
|
||||
defaults={'enabled': True},
|
||||
)[0]
|
||||
|
||||
|
||||
def get_authenticators():
|
||||
from authentic2.apps.authenticators.models import BaseAuthenticator, LoginPasswordAuthenticator
|
||||
from authentic2.apps.authenticators.models import BaseAuthenticator
|
||||
|
||||
backends = list(
|
||||
BaseAuthenticator.authenticators.filter(enabled=True).exclude(slug='password-authenticator')
|
||||
)
|
||||
password_backend, dummy = LoginPasswordAuthenticator.objects.get_or_create(
|
||||
slug='password-authenticator',
|
||||
defaults={'enabled': True},
|
||||
)
|
||||
password_backend = get_password_authenticator()
|
||||
if password_backend.enabled:
|
||||
backends.append(password_backend)
|
||||
|
||||
|
|
|
@ -401,6 +401,12 @@ def login(request, template_name='authentic2/login.html', redirect_field_name=RE
|
|||
|
||||
authenticators = utils_misc.get_authenticators()
|
||||
|
||||
password_authenticators = [x for x in authenticators if x.slug == 'password-authenticator']
|
||||
if not password_authenticators:
|
||||
registration_open = False
|
||||
else:
|
||||
registration_open = password_authenticators[0].registration_open
|
||||
|
||||
blocks = []
|
||||
|
||||
registration_url = utils_misc.get_registration_url(request)
|
||||
|
@ -408,7 +414,7 @@ def login(request, template_name='authentic2/login.html', redirect_field_name=RE
|
|||
context = {
|
||||
'cancel': app_settings.A2_LOGIN_DISPLAY_A_CANCEL_BUTTON and nonce is not None,
|
||||
'can_reset_password': app_settings.A2_USER_CAN_RESET_PASSWORD is not False,
|
||||
'registration_authorized': getattr(settings, 'REGISTRATION_OPEN', True),
|
||||
'registration_authorized': registration_open,
|
||||
'registration_url': registration_url,
|
||||
}
|
||||
|
||||
|
@ -864,6 +870,7 @@ class PasswordResetView(FormView):
|
|||
|
||||
def get_form_kwargs(self, **kwargs):
|
||||
kwargs = super().get_form_kwargs(**kwargs)
|
||||
kwargs['password_authenticator'] = utils_misc.get_password_authenticator()
|
||||
initial = kwargs.setdefault('initial', {})
|
||||
initial['next_url'] = utils_misc.select_next_url(self.request, '')
|
||||
return kwargs
|
||||
|
@ -1109,7 +1116,8 @@ class BaseRegistrationView(HomeURLMixin, FormView):
|
|||
title = _('Registration')
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not getattr(settings, 'REGISTRATION_OPEN', True):
|
||||
password_authenticator = utils_misc.get_password_authenticator()
|
||||
if not password_authenticator.registration_open:
|
||||
raise Http404('Registration is not open.')
|
||||
|
||||
self.token = {}
|
||||
|
|
|
@ -409,7 +409,6 @@ def test_login_csrf_no_middleware(app, simple_user, settings):
|
|||
|
||||
def test_login_error_messages(app, settings, simple_user):
|
||||
settings.A2_USER_CAN_RESET_PASSWORD = True
|
||||
settings.REGISTRATION_OPEN = True
|
||||
resp = app.get('/login/')
|
||||
resp.form.set('username', 'x')
|
||||
resp.form.set('password', 'y')
|
||||
|
@ -419,7 +418,7 @@ def test_login_error_messages(app, settings, simple_user):
|
|||
assert 'or create an account.' in resp
|
||||
|
||||
settings.A2_USER_CAN_RESET_PASSWORD = False
|
||||
settings.REGISTRATION_OPEN = False
|
||||
LoginPasswordAuthenticator.objects.update(registration_open=False)
|
||||
resp.form.set('username', 'x')
|
||||
resp.form.set('password', 'y')
|
||||
resp = resp.form.submit(name='login-password-submit')
|
||||
|
@ -428,7 +427,6 @@ def test_login_error_messages(app, settings, simple_user):
|
|||
assert 'or create an account.' not in resp
|
||||
|
||||
settings.A2_USER_CAN_RESET_PASSWORD = True
|
||||
settings.REGISTRATION_OPEN = False
|
||||
resp.form.set('username', 'x')
|
||||
resp.form.set('password', 'y')
|
||||
resp = resp.form.submit(name='login-password-submit')
|
||||
|
@ -437,7 +435,7 @@ def test_login_error_messages(app, settings, simple_user):
|
|||
assert 'or create an account.' not in resp
|
||||
|
||||
settings.A2_USER_CAN_RESET_PASSWORD = False
|
||||
settings.REGISTRATION_OPEN = True
|
||||
LoginPasswordAuthenticator.objects.update(registration_open=True)
|
||||
resp.form.set('username', 'x')
|
||||
resp.form.set('password', 'y')
|
||||
resp = resp.form.submit(name='login-password-submit')
|
||||
|
|
|
@ -22,6 +22,7 @@ from django.test.utils import override_settings
|
|||
from django.urls import reverse
|
||||
from httmock import HTTMock, remember_called, urlmatch
|
||||
|
||||
from authentic2.apps.authenticators.models import LoginPasswordAuthenticator
|
||||
from authentic2.models import SMSCode, Token
|
||||
from authentic2.utils.misc import send_password_reset_mail
|
||||
|
||||
|
@ -290,7 +291,7 @@ def test_old_url_redirect(app, db):
|
|||
[True, False],
|
||||
)
|
||||
def test_send_password_reset_email_no_account(app, db, mailoutbox, settings, registration_open):
|
||||
settings.REGISTRATION_OPEN = registration_open
|
||||
LoginPasswordAuthenticator.objects.update(registration_open=registration_open)
|
||||
resp = app.get('/password/reset/?next=/whatever/', status=200)
|
||||
resp.form.set('email', 'test@entrouvert.com')
|
||||
resp = resp.form.submit()
|
||||
|
@ -299,7 +300,7 @@ def test_send_password_reset_email_no_account(app, db, mailoutbox, settings, reg
|
|||
assert mail.subject == 'Password reset on testserver'
|
||||
for body in (mail.body, mail.alternatives[0][0]):
|
||||
assert 'no account was found associated with this address' in body
|
||||
if settings.REGISTRATION_OPEN:
|
||||
if registration_open:
|
||||
assert 'https://testserver/register/' in body
|
||||
# check next_url was preserved
|
||||
assert 'next=/whatever/' in body
|
||||
|
|
Loading…
Reference in New Issue