mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-28 11:36:44 +00:00
Refactor auth adaptations into dedicated file (#8687)
* Update docker.yaml (#278) * reset * rename functions to better reflect function * move authentication behaviour overrides to explicit file * fix import order * fix import path
This commit is contained in:
parent
acb756eacc
commit
8fcb3c2506
@ -1,11 +1,11 @@
|
|||||||
"""Helper forms which subclass Django forms to provide additional functionality."""
|
"""Overrides for allauth and adjacent packages to enforce InvenTree specific auth settings and restirctions."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import Group, User
|
from django.contrib.auth.models import Group
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@ -17,9 +17,6 @@ from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
|
|||||||
from allauth_2fa.adapter import OTPAdapter
|
from allauth_2fa.adapter import OTPAdapter
|
||||||
from allauth_2fa.forms import TOTPDeviceForm
|
from allauth_2fa.forms import TOTPDeviceForm
|
||||||
from allauth_2fa.utils import user_has_valid_totp_device
|
from allauth_2fa.utils import user_has_valid_totp_device
|
||||||
from crispy_forms.bootstrap import AppendedText, PrependedAppendedText, PrependedText
|
|
||||||
from crispy_forms.helper import FormHelper
|
|
||||||
from crispy_forms.layout import Field, Layout
|
|
||||||
from dj_rest_auth.registration.serializers import RegisterSerializer
|
from dj_rest_auth.registration.serializers import RegisterSerializer
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
@ -31,115 +28,6 @@ from InvenTree.exceptions import log_error
|
|||||||
logger = logging.getLogger('inventree')
|
logger = logging.getLogger('inventree')
|
||||||
|
|
||||||
|
|
||||||
class HelperForm(forms.ModelForm):
|
|
||||||
"""Provides simple integration of crispy_forms extension."""
|
|
||||||
|
|
||||||
# Custom field decorations can be specified here, per form class
|
|
||||||
field_prefix = {}
|
|
||||||
field_suffix = {}
|
|
||||||
field_placeholder = {}
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
"""Setup layout."""
|
|
||||||
super(forms.ModelForm, self).__init__(*args, **kwargs)
|
|
||||||
self.helper = FormHelper()
|
|
||||||
|
|
||||||
self.helper.form_tag = False
|
|
||||||
self.helper.form_show_errors = True
|
|
||||||
|
|
||||||
"""
|
|
||||||
Create a default 'layout' for this form.
|
|
||||||
Ref: https://django-crispy-forms.readthedocs.io/en/latest/layouts.html
|
|
||||||
This is required to do fancy things later (like adding PrependedText, etc).
|
|
||||||
|
|
||||||
Simply create a 'blank' layout for each available field.
|
|
||||||
"""
|
|
||||||
|
|
||||||
self.rebuild_layout()
|
|
||||||
|
|
||||||
def rebuild_layout(self):
|
|
||||||
"""Build crispy layout out of current fields."""
|
|
||||||
layouts = []
|
|
||||||
|
|
||||||
for field in self.fields:
|
|
||||||
prefix = self.field_prefix.get(field, None)
|
|
||||||
suffix = self.field_suffix.get(field, None)
|
|
||||||
placeholder = self.field_placeholder.get(field, '')
|
|
||||||
|
|
||||||
# Look for font-awesome icons
|
|
||||||
if prefix and prefix.startswith('fa-'):
|
|
||||||
prefix = f"<i class='fas {prefix}'/>"
|
|
||||||
|
|
||||||
if suffix and suffix.startswith('fa-'):
|
|
||||||
suffix = f"<i class='fas {suffix}'/>"
|
|
||||||
|
|
||||||
if prefix and suffix:
|
|
||||||
layouts.append(
|
|
||||||
Field(
|
|
||||||
PrependedAppendedText(
|
|
||||||
field,
|
|
||||||
prepended_text=prefix,
|
|
||||||
appended_text=suffix,
|
|
||||||
placeholder=placeholder,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
elif prefix:
|
|
||||||
layouts.append(
|
|
||||||
Field(PrependedText(field, prefix, placeholder=placeholder))
|
|
||||||
)
|
|
||||||
|
|
||||||
elif suffix:
|
|
||||||
layouts.append(
|
|
||||||
Field(AppendedText(field, suffix, placeholder=placeholder))
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
|
||||||
layouts.append(Field(field, placeholder=placeholder))
|
|
||||||
|
|
||||||
self.helper.layout = Layout(*layouts)
|
|
||||||
|
|
||||||
|
|
||||||
class SetPasswordForm(HelperForm):
|
|
||||||
"""Form for setting user password."""
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
"""Metaclass options."""
|
|
||||||
|
|
||||||
model = User
|
|
||||||
fields = ['enter_password', 'confirm_password', 'old_password']
|
|
||||||
|
|
||||||
enter_password = forms.CharField(
|
|
||||||
max_length=100,
|
|
||||||
min_length=8,
|
|
||||||
required=True,
|
|
||||||
initial='',
|
|
||||||
widget=forms.PasswordInput(attrs={'autocomplete': 'off'}),
|
|
||||||
label=_('Enter password'),
|
|
||||||
help_text=_('Enter new password'),
|
|
||||||
)
|
|
||||||
|
|
||||||
confirm_password = forms.CharField(
|
|
||||||
max_length=100,
|
|
||||||
min_length=8,
|
|
||||||
required=True,
|
|
||||||
initial='',
|
|
||||||
widget=forms.PasswordInput(attrs={'autocomplete': 'off'}),
|
|
||||||
label=_('Confirm password'),
|
|
||||||
help_text=_('Confirm new password'),
|
|
||||||
)
|
|
||||||
|
|
||||||
old_password = forms.CharField(
|
|
||||||
label=_('Old password'),
|
|
||||||
strip=False,
|
|
||||||
required=False,
|
|
||||||
widget=forms.PasswordInput(
|
|
||||||
attrs={'autocomplete': 'current-password', 'autofocus': True}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# override allauth
|
# override allauth
|
||||||
class CustomLoginForm(LoginForm):
|
class CustomLoginForm(LoginForm):
|
||||||
"""Custom login form to override default allauth behaviour."""
|
"""Custom login form to override default allauth behaviour."""
|
||||||
@ -214,7 +102,10 @@ class CustomTOTPDeviceForm(TOTPDeviceForm):
|
|||||||
|
|
||||||
def registration_enabled():
|
def registration_enabled():
|
||||||
"""Determine whether user registration is enabled."""
|
"""Determine whether user registration is enabled."""
|
||||||
if get_global_setting('LOGIN_ENABLE_REG') or InvenTree.sso.registration_enabled():
|
if (
|
||||||
|
get_global_setting('LOGIN_ENABLE_REG')
|
||||||
|
or InvenTree.sso.sso_registration_enabled()
|
||||||
|
):
|
||||||
if settings.EMAIL_HOST:
|
if settings.EMAIL_HOST:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@ -316,10 +207,8 @@ class CustomAccountAdapter(
|
|||||||
|
|
||||||
def get_email_confirmation_url(self, request, emailconfirmation):
|
def get_email_confirmation_url(self, request, emailconfirmation):
|
||||||
"""Construct the email confirmation url."""
|
"""Construct the email confirmation url."""
|
||||||
from InvenTree.helpers_model import construct_absolute_url
|
|
||||||
|
|
||||||
url = super().get_email_confirmation_url(request, emailconfirmation)
|
url = super().get_email_confirmation_url(request, emailconfirmation)
|
||||||
url = construct_absolute_url(url)
|
url = InvenTree.helpers_model.construct_absolute_url(url)
|
||||||
return url
|
return url
|
||||||
|
|
||||||
|
|
@ -592,7 +592,7 @@ REST_AUTH = {
|
|||||||
|
|
||||||
OLD_PASSWORD_FIELD_ENABLED = True
|
OLD_PASSWORD_FIELD_ENABLED = True
|
||||||
REST_AUTH_REGISTER_SERIALIZERS = {
|
REST_AUTH_REGISTER_SERIALIZERS = {
|
||||||
'REGISTER_SERIALIZER': 'InvenTree.forms.CustomRegisterSerializer'
|
'REGISTER_SERIALIZER': 'InvenTree.auth_overrides.CustomRegisterSerializer'
|
||||||
}
|
}
|
||||||
|
|
||||||
# JWT settings - rest_framework_simplejwt
|
# JWT settings - rest_framework_simplejwt
|
||||||
@ -1312,8 +1312,8 @@ REMOVE_SUCCESS_URL = 'settings'
|
|||||||
|
|
||||||
# override forms / adapters
|
# override forms / adapters
|
||||||
ACCOUNT_FORMS = {
|
ACCOUNT_FORMS = {
|
||||||
'login': 'InvenTree.forms.CustomLoginForm',
|
'login': 'InvenTree.auth_overrides.CustomLoginForm',
|
||||||
'signup': 'InvenTree.forms.CustomSignupForm',
|
'signup': 'InvenTree.auth_overrides.CustomSignupForm',
|
||||||
'add_email': 'allauth.account.forms.AddEmailForm',
|
'add_email': 'allauth.account.forms.AddEmailForm',
|
||||||
'change_password': 'allauth.account.forms.ChangePasswordForm',
|
'change_password': 'allauth.account.forms.ChangePasswordForm',
|
||||||
'set_password': 'allauth.account.forms.SetPasswordForm',
|
'set_password': 'allauth.account.forms.SetPasswordForm',
|
||||||
@ -1321,12 +1321,12 @@ ACCOUNT_FORMS = {
|
|||||||
'reset_password_from_key': 'allauth.account.forms.ResetPasswordKeyForm',
|
'reset_password_from_key': 'allauth.account.forms.ResetPasswordKeyForm',
|
||||||
'disconnect': 'allauth.socialaccount.forms.DisconnectForm',
|
'disconnect': 'allauth.socialaccount.forms.DisconnectForm',
|
||||||
}
|
}
|
||||||
ALLAUTH_2FA_FORMS = {'setup': 'InvenTree.forms.CustomTOTPDeviceForm'}
|
ALLAUTH_2FA_FORMS = {'setup': 'InvenTree.auth_overrides.CustomTOTPDeviceForm'}
|
||||||
# Determine if multi-factor authentication is enabled for this server (default = True)
|
# Determine if multi-factor authentication is enabled for this server (default = True)
|
||||||
MFA_ENABLED = get_boolean_setting('INVENTREE_MFA_ENABLED', 'mfa_enabled', True)
|
MFA_ENABLED = get_boolean_setting('INVENTREE_MFA_ENABLED', 'mfa_enabled', True)
|
||||||
|
|
||||||
SOCIALACCOUNT_ADAPTER = 'InvenTree.forms.CustomSocialAccountAdapter'
|
SOCIALACCOUNT_ADAPTER = 'InvenTree.auth_overrides.CustomSocialAccountAdapter'
|
||||||
ACCOUNT_ADAPTER = 'InvenTree.forms.CustomAccountAdapter'
|
ACCOUNT_ADAPTER = 'InvenTree.auth_overrides.CustomAccountAdapter'
|
||||||
|
|
||||||
# Markdownify configuration
|
# Markdownify configuration
|
||||||
# Ref: https://django-markdownify.readthedocs.io/en/latest/settings.html
|
# Ref: https://django-markdownify.readthedocs.io/en/latest/settings.html
|
||||||
|
@ -198,8 +198,8 @@ class SocialProviderListView(ListAPI):
|
|||||||
provider_list.append(provider_data)
|
provider_list.append(provider_data)
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'sso_enabled': InvenTree.sso.login_enabled(),
|
'sso_enabled': InvenTree.sso.sso_login_enabled(),
|
||||||
'sso_registration': InvenTree.sso.registration_enabled(),
|
'sso_registration': InvenTree.sso.sso_registration_enabled(),
|
||||||
'mfa_required': settings.MFA_ENABLED
|
'mfa_required': settings.MFA_ENABLED
|
||||||
and get_global_setting('LOGIN_ENFORCE_MFA'),
|
and get_global_setting('LOGIN_ENFORCE_MFA'),
|
||||||
'mfa_enabled': settings.MFA_ENABLED,
|
'mfa_enabled': settings.MFA_ENABLED,
|
||||||
|
@ -69,12 +69,12 @@ def provider_display_name(provider):
|
|||||||
return provider.name
|
return provider.name
|
||||||
|
|
||||||
|
|
||||||
def login_enabled() -> bool:
|
def sso_login_enabled() -> bool:
|
||||||
"""Return True if SSO login is enabled."""
|
"""Return True if SSO login is enabled."""
|
||||||
return str2bool(get_global_setting('LOGIN_ENABLE_SSO'))
|
return str2bool(get_global_setting('LOGIN_ENABLE_SSO'))
|
||||||
|
|
||||||
|
|
||||||
def registration_enabled() -> bool:
|
def sso_registration_enabled() -> bool:
|
||||||
"""Return True if SSO registration is enabled."""
|
"""Return True if SSO registration is enabled."""
|
||||||
return str2bool(get_global_setting('LOGIN_ENABLE_SSO_REG'))
|
return str2bool(get_global_setting('LOGIN_ENABLE_SSO_REG'))
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ from allauth.socialaccount.models import SocialAccount, SocialLogin
|
|||||||
|
|
||||||
from common.models import InvenTreeSetting
|
from common.models import InvenTreeSetting
|
||||||
from InvenTree import sso
|
from InvenTree import sso
|
||||||
from InvenTree.forms import RegistratonMixin
|
from InvenTree.auth_overrides import RegistratonMixin
|
||||||
|
|
||||||
|
|
||||||
class Dummy:
|
class Dummy:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user