Source code for shuup.front.apps.auth.forms

# -*- coding: utf-8 -*-
# This file is part of Shuup.
#
# Copyright (c) 2012-2021, Shuup Commerce Inc. All rights reserved.
#
# This source code is licensed under the OSL-3.0 license found in the
# LICENSE file in the root directory of this source tree.
from django import forms
from django.conf import settings
from django.contrib.auth import authenticate, get_user_model
from django.contrib.auth.forms import AuthenticationForm
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from django.utils.translation import ugettext_lazy as _

from shuup.apps.provides import get_provide_objects
from shuup.core.models import get_person_contact
from shuup.front.signals import login_allowed


[docs]class EmailAuthenticationForm(AuthenticationForm): error_messages = { "invalid_login": _( "Error! Please enter a correct %(username)s and password. " "Note that both fields may be case-sensitive. " "In case of multiple accounts with same email only username can be used to log in." ), "inactive": _("This account is inactive."), } def __init__(self, *args, **kwargs): super(EmailAuthenticationForm, self).__init__(*args, **kwargs) self.fields["username"].label = _("Username or email address") for provider_cls in get_provide_objects("front_auth_form_field_provider"): provider = provider_cls() for definition in provider.get_fields(request=self.request): self.fields[definition.name] = definition.field
[docs] def clean_username(self): username = self.cleaned_data["username"] user_model = get_user_model() # Note: Always search by username AND by email prevent timing attacks try: user_by_name = user_model._default_manager.get_by_natural_key(username) except ObjectDoesNotExist: user_by_name = None try: user_by_email = user_model._default_manager.get(email=username) except (ObjectDoesNotExist, MultipleObjectsReturned): user_by_email = None if not user_by_name and user_by_email: return getattr(user_by_email, user_model.USERNAME_FIELD) return username
[docs] def clean(self): username = self.cleaned_data.get("username") password = self.cleaned_data.get("password") if username and password: self.user_cache = authenticate(request=self.request, username=username, password=password) # So here even with invalid login and user cache being None # we want to check whether the user we are trying to # login is inactive or not. try: user_temp = get_user_model().objects.get(username=username) except ObjectDoesNotExist: user_temp = None if user_temp is not None: self.confirm_login_allowed(user_temp) # Back to default behavior. Meaning that we want to always # raise for invalid login incase the authenticate failed if self.user_cache is None: raise forms.ValidationError( self.error_messages["invalid_login"], code="invalid_login", params={"username": self.username_field.verbose_name}, )
[docs] def confirm_login_allowed(self, user): """ Do not let inactive person contact user to login. """ if not get_person_contact(user).is_active: raise forms.ValidationError( self.error_messages["inactive"], code="inactive", ) if settings.SHUUP_ENABLE_MULTIPLE_SHOPS and settings.SHUUP_MANAGE_CONTACTS_PER_SHOP: if not user.is_superuser: shop = self.request.shop if shop not in user.contact.shops.all(): raise forms.ValidationError(_("You are not allowed to log in to this shop.")) super(EmailAuthenticationForm, self).confirm_login_allowed(user) login_allowed.send(sender=type(self), request=self.request, user=user)