Modules Python django.contrib.auth.{__init__, models, base_user, mixins, urls, decorators, context_processors}.py

Module Python django/contrib/auth/__init__.py

  1import inspect
  2import re
  3
  4from django.apps import apps as django_apps
  5from django.conf import settings
  6from django.core.exceptions import ImproperlyConfigured
  7from django.core.exceptions import PermissionDenied
  8from django.middleware.csrf import rotate_token
  9from django.utils.crypto import constant_time_compare
 10from django.utils.module_loading import import_string
 11
 12from .signals import user_logged_in
 13from .signals import user_logged_out
 14from .signals import user_login_failed
 15
 16SESSION_KEY = "_auth_user_id"
 17BACKEND_SESSION_KEY = "_auth_user_backend"
 18HASH_SESSION_KEY = "_auth_user_hash"
 19REDIRECT_FIELD_NAME = "next"
 20
 21
 22def load_backend(path):
 23    return import_string(path)()
 24
 25
 26def _get_backends(return_tuples=False):
 27    backends = []
 28    for backend_path in settings.AUTHENTICATION_BACKENDS:
 29        backend = load_backend(backend_path)
 30        backends.append((backend, backend_path) if return_tuples else backend)
 31    if not backends:
 32        raise ImproperlyConfigured(
 33            "No authentication backends have been defined. Does "
 34            "AUTHENTICATION_BACKENDS contain anything?"
 35        )
 36    return backends
 37
 38
 39def get_backends():
 40    return _get_backends(return_tuples=False)
 41
 42
 43def _clean_credentials(credentials):
 44    """
 45    Clean a dictionary of credentials of potentially sensitive info before
 46    sending to less secure functions.
 47
 48    Not comprehensive - intended for user_login_failed signal
 49    """
 50    SENSITIVE_CREDENTIALS = re.compile("api|token|key|secret|password|signature", re.I)
 51    CLEANSED_SUBSTITUTE = "********************"
 52    for key in credentials:
 53        if SENSITIVE_CREDENTIALS.search(key):
 54            credentials[key] = CLEANSED_SUBSTITUTE
 55    return credentials
 56
 57
 58def _get_user_session_key(request):
 59    # This value in the session is always serialized to a string, so we need
 60    # to convert it back to Python whenever we access it.
 61    return get_user_model()._meta.pk.to_python(request.session[SESSION_KEY])
 62
 63
 64def authenticate(request=None, **credentials):
 65    """
 66    If the given credentials are valid, return a User object.
 67    """
 68    for backend, backend_path in _get_backends(return_tuples=True):
 69        try:
 70            inspect.getcallargs(backend.authenticate, request, **credentials)
 71        except TypeError:
 72            # This backend doesn't accept these credentials as arguments. Try the next one.
 73            continue
 74        try:
 75            user = backend.authenticate(request, **credentials)
 76        except PermissionDenied:
 77            # This backend says to stop in our tracks - this user should not be allowed in at all.
 78            break
 79        if user is None:
 80            continue
 81        # Annotate the user object with the path of the backend.
 82        user.backend = backend_path
 83        return user
 84
 85    # The credentials supplied are invalid to all backends, fire signal
 86    user_login_failed.send(
 87        sender=__name__, credentials=_clean_credentials(credentials), request=request
 88    )
 89
 90
 91def login(request, user, backend=None):
 92    """
 93    Persist a user id and a backend in the request. This way a user doesn't
 94    have to reauthenticate on every request. Note that data set during
 95    the anonymous session is retained when the user logs in.
 96    """
 97    session_auth_hash = ""
 98    if user is None:
 99        user = request.user
100    if hasattr(user, "get_session_auth_hash"):
101        session_auth_hash = user.get_session_auth_hash()
102
103    if SESSION_KEY in request.session:
104        if _get_user_session_key(request) != user.pk or (
105            session_auth_hash
106            and not constant_time_compare(
107                request.session.get(HASH_SESSION_KEY, ""), session_auth_hash
108            )
109        ):
110            # To avoid reusing another user's session, create a new, empty
111            # session if the existing session corresponds to a different
112            # authenticated user.
113            request.session.flush()
114    else:
115        request.session.cycle_key()
116
117    try:
118        backend = backend or user.backend
119    except AttributeError:
120        backends = _get_backends(return_tuples=True)
121        if len(backends) == 1:
122            _, backend = backends[0]
123        else:
124            raise ValueError(
125                "You have multiple authentication backends configured and "
126                "therefore must provide the `backend` argument or set the "
127                "`backend` attribute on the user."
128            )
129    else:
130        if not isinstance(backend, str):
131            raise TypeError(
132                "backend must be a dotted import path string (got %r)." % backend
133            )
134
135    request.session[SESSION_KEY] = user._meta.pk.value_to_string(user)
136    request.session[BACKEND_SESSION_KEY] = backend
137    request.session[HASH_SESSION_KEY] = session_auth_hash
138    if hasattr(request, "user"):
139        request.user = user
140    rotate_token(request)
141    user_logged_in.send(sender=user.__class__, request=request, user=user)
142
143
144def logout(request):
145    """
146    Remove the authenticated user's ID from the request and flush their session
147    data.
148    """
149    # Dispatch the signal before the user is logged out so the receivers have a
150    # chance to find out *who* logged out.
151    user = getattr(request, "user", None)
152    if not getattr(user, "is_authenticated", True):
153        user = None
154    user_logged_out.send(sender=user.__class__, request=request, user=user)
155    request.session.flush()
156    if hasattr(request, "user"):
157        from django.contrib.auth.models import AnonymousUser
158
159        request.user = AnonymousUser()
160
161
162def get_user_model():
163    """
164    Return the User model that is active in this project.
165    """
166    try:
167        return django_apps.get_model(settings.AUTH_USER_MODEL, require_ready=False)
168    except ValueError:
169        raise ImproperlyConfigured(
170            "AUTH_USER_MODEL must be of the form 'app_label.model_name'"
171        )
172    except LookupError:
173        raise ImproperlyConfigured(
174            "AUTH_USER_MODEL refers to model '%s' that has not been installed"
175            % settings.AUTH_USER_MODEL
176        )
177
178
179def get_user(request):
180    """
181    Return the user model instance associated with the given request session.
182    If no user is retrieved, return an instance of `AnonymousUser`.
183    """
184    from .models import AnonymousUser
185
186    user = None
187    try:
188        user_id = _get_user_session_key(request)
189        backend_path = request.session[BACKEND_SESSION_KEY]
190    except KeyError:
191        pass
192    else:
193        if backend_path in settings.AUTHENTICATION_BACKENDS:
194            backend = load_backend(backend_path)
195            user = backend.get_user(user_id)
196            # Verify the session
197            if hasattr(user, "get_session_auth_hash"):
198                session_hash = request.session.get(HASH_SESSION_KEY)
199                session_hash_verified = session_hash and constant_time_compare(
200                    session_hash, user.get_session_auth_hash()
201                )
202                if not session_hash_verified:
203                    request.session.flush()
204                    user = None
205
206    return user or AnonymousUser()
207
208
209def get_permission_codename(action, opts):
210    """
211    Return the codename of the permission for the specified action.
212    """
213    return "%s_%s" % (action, opts.model_name)
214
215
216def update_session_auth_hash(request, user):
217    """
218    Updating a user's password logs out all sessions for the user.
219
220    Take the current request and the updated user object from which the new
221    session hash will be derived and update the session hash appropriately to
222    prevent a password change from logging out the session from which the
223    password was changed.
224    """
225    request.session.cycle_key()
226    if hasattr(user, "get_session_auth_hash") and request.user == user:
227        request.session[HASH_SESSION_KEY] = user.get_session_auth_hash()
228
229
230default_app_config = "django.contrib.auth.apps.AuthConfig"

Module Python django/contrib/auth/models.py

  1from django.contrib import auth
  2from django.contrib.auth.base_user import AbstractBaseUser
  3from django.contrib.auth.base_user import BaseUserManager
  4from django.contrib.contenttypes.models import ContentType
  5from django.core.exceptions import PermissionDenied
  6from django.core.mail import send_mail
  7from django.db import models
  8from django.db.models.manager import EmptyManager
  9from django.utils import timezone
 10from django.utils.translation import gettext_lazy as _
 11
 12from .validators import UnicodeUsernameValidator
 13
 14
 15def update_last_login(sender, user, **kwargs):
 16    """
 17    A signal receiver which updates the last_login date for
 18    the user logging in.
 19    """
 20    user.last_login = timezone.now()
 21    user.save(update_fields=["last_login"])
 22
 23
 24class PermissionManager(models.Manager):
 25    use_in_migrations = True
 26
 27    def get_by_natural_key(self, codename, app_label, model):
 28        return self.get(
 29            codename=codename,
 30            content_type=ContentType.objects.db_manager(self.db).get_by_natural_key(
 31                app_label, model
 32            ),
 33        )
 34
 35
 36class Permission(models.Model):
 37    """
 38    The permissions system provides a way to assign permissions to specific
 39    users and groups of users.
 40
 41    The permission system is used by the Django admin site, but may also be
 42    useful in your own code. The Django admin site uses permissions as follows:
 43
 44        - The "add" permission limits the user's ability to view the "add" form
 45          and add an object.
 46        - The "change" permission limits a user's ability to view the change
 47          list, view the "change" form and change an object.
 48        - The "delete" permission limits the ability to delete an object.
 49        - The "view" permission limits the ability to view an object.
 50
 51    Permissions are set globally per type of object, not per specific object
 52    instance. It is possible to say "Mary may change news stories," but it's
 53    not currently possible to say "Mary may change news stories, but only the
 54    ones she created herself" or "Mary may only change news stories that have a
 55    certain status or publication date."
 56
 57    The permissions listed above are automatically created for each model.
 58    """
 59
 60    name = models.CharField(_("name"), max_length=255)
 61    content_type = models.ForeignKey(
 62        ContentType, models.CASCADE, verbose_name=_("content type")
 63    )
 64    codename = models.CharField(_("codename"), max_length=100)
 65
 66    objects = PermissionManager()
 67
 68    class Meta:
 69        verbose_name = _("permission")
 70        verbose_name_plural = _("permissions")
 71        unique_together = (("content_type", "codename"),)
 72        ordering = ("content_type__app_label", "content_type__model", "codename")
 73
 74    def __str__(self):
 75        return "%s | %s" % (self.content_type, self.name)
 76
 77    def natural_key(self):
 78        return (self.codename,) + self.content_type.natural_key()
 79
 80    natural_key.dependencies = ["contenttypes.contenttype"]
 81
 82
 83class GroupManager(models.Manager):
 84    """
 85    The manager for the auth's Group model.
 86    """
 87
 88    use_in_migrations = True
 89
 90    def get_by_natural_key(self, name):
 91        return self.get(name=name)
 92
 93
 94class Group(models.Model):
 95    """
 96    Groups are a generic way of categorizing users to apply permissions, or
 97    some other label, to those users. A user can belong to any number of
 98    groups.
 99
100    A user in a group automatically has all the permissions granted to that
101    group. For example, if the group 'Site editors' has the permission
102    can_edit_home_page, any user in that group will have that permission.
103
104    Beyond permissions, groups are a convenient way to categorize users to
105    apply some label, or extended functionality, to them. For example, you
106    could create a group 'Special users', and you could write code that would
107    do special things to those users -- such as giving them access to a
108    members-only portion of your site, or sending them members-only email
109    messages.
110    """
111
112    name = models.CharField(_("name"), max_length=150, unique=True)
113    permissions = models.ManyToManyField(
114        Permission, verbose_name=_("permissions"), blank=True
115    )
116
117    objects = GroupManager()
118
119    class Meta:
120        verbose_name = _("group")
121        verbose_name_plural = _("groups")
122
123    def __str__(self):
124        return self.name
125
126    def natural_key(self):
127        return (self.name,)
128
129
130class UserManager(BaseUserManager):
131    use_in_migrations = True
132
133    def _create_user(self, username, email, password, **extra_fields):
134        """
135        Create and save a user with the given username, email, and password.
136        """
137        if not username:
138            raise ValueError("The given username must be set")
139        email = self.normalize_email(email)
140        username = self.model.normalize_username(username)
141        user = self.model(username=username, email=email, **extra_fields)
142        user.set_password(password)
143        user.save(using=self._db)
144        return user
145
146    def create_user(self, username, email=None, password=None, **extra_fields):
147        extra_fields.setdefault("is_staff", False)
148        extra_fields.setdefault("is_superuser", False)
149        return self._create_user(username, email, password, **extra_fields)
150
151    def create_superuser(self, username, email, password, **extra_fields):
152        extra_fields.setdefault("is_staff", True)
153        extra_fields.setdefault("is_superuser", True)
154
155        if extra_fields.get("is_staff") is not True:
156            raise ValueError("Superuser must have is_staff=True.")
157        if extra_fields.get("is_superuser") is not True:
158            raise ValueError("Superuser must have is_superuser=True.")
159
160        return self._create_user(username, email, password, **extra_fields)
161
162
163# A few helper functions for common logic between User and AnonymousUser.
164def _user_get_all_permissions(user, obj):
165    permissions = set()
166    for backend in auth.get_backends():
167        if hasattr(backend, "get_all_permissions"):
168            permissions.update(backend.get_all_permissions(user, obj))
169    return permissions
170
171
172def _user_has_perm(user, perm, obj):
173    """
174    A backend can raise `PermissionDenied` to short-circuit permission checking.
175    """
176    for backend in auth.get_backends():
177        if not hasattr(backend, "has_perm"):
178            continue
179        try:
180            if backend.has_perm(user, perm, obj):
181                return True
182        except PermissionDenied:
183            return False
184    return False
185
186
187def _user_has_module_perms(user, app_label):
188    """
189    A backend can raise `PermissionDenied` to short-circuit permission checking.
190    """
191    for backend in auth.get_backends():
192        if not hasattr(backend, "has_module_perms"):
193            continue
194        try:
195            if backend.has_module_perms(user, app_label):
196                return True
197        except PermissionDenied:
198            return False
199    return False
200
201
202class PermissionsMixin(models.Model):
203    """
204    Add the fields and methods necessary to support the Group and Permission
205    models using the ModelBackend.
206    """
207
208    is_superuser = models.BooleanField(
209        _("superuser status"),
210        default=False,
211        help_text=_(
212            "Designates that this user has all permissions without "
213            "explicitly assigning them."
214        ),
215    )
216    groups = models.ManyToManyField(
217        Group,
218        verbose_name=_("groups"),
219        blank=True,
220        help_text=_(
221            "The groups this user belongs to. A user will get all permissions "
222            "granted to each of their groups."
223        ),
224        related_name="user_set",
225        related_query_name="user",
226    )
227    user_permissions = models.ManyToManyField(
228        Permission,
229        verbose_name=_("user permissions"),
230        blank=True,
231        help_text=_("Specific permissions for this user."),
232        related_name="user_set",
233        related_query_name="user",
234    )
235
236    class Meta:
237        abstract = True
238
239    def get_group_permissions(self, obj=None):
240        """
241        Return a list of permission strings that this user has through their
242        groups. Query all available auth backends. If an object is passed in,
243        return only permissions matching this object.
244        """
245        permissions = set()
246        for backend in auth.get_backends():
247            if hasattr(backend, "get_group_permissions"):
248                permissions.update(backend.get_group_permissions(self, obj))
249        return permissions
250
251    def get_all_permissions(self, obj=None):
252        return _user_get_all_permissions(self, obj)
253
254    def has_perm(self, perm, obj=None):
255        """
256        Return True if the user has the specified permission. Query all
257        available auth backends, but return immediately if any backend returns
258        True. Thus, a user who has permission from a single auth backend is
259        assumed to have permission in general. If an object is provided, check
260        permissions for that object.
261        """
262        # Active superusers have all permissions.
263        if self.is_active and self.is_superuser:
264            return True
265
266        # Otherwise we need to check the backends.
267        return _user_has_perm(self, perm, obj)
268
269    def has_perms(self, perm_list, obj=None):
270        """
271        Return True if the user has each of the specified permissions. If
272        object is passed, check if the user has all required perms for it.
273        """
274        return all(self.has_perm(perm, obj) for perm in perm_list)
275
276    def has_module_perms(self, app_label):
277        """
278        Return True if the user has any permissions in the given app label.
279        Use similar logic as has_perm(), above.
280        """
281        # Active superusers have all permissions.
282        if self.is_active and self.is_superuser:
283            return True
284
285        return _user_has_module_perms(self, app_label)
286
287
288class AbstractUser(AbstractBaseUser, PermissionsMixin):
289    """
290    An abstract base class implementing a fully featured User model with
291    admin-compliant permissions.
292
293    Username and password are required. Other fields are optional.
294    """
295
296    username_validator = UnicodeUsernameValidator()
297
298    username = models.CharField(
299        _("username"),
300        max_length=150,
301        unique=True,
302        help_text=_(
303            "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only."
304        ),
305        validators=[username_validator],
306        error_messages={"unique": _("A user with that username already exists.")},
307    )
308    first_name = models.CharField(_("first name"), max_length=30, blank=True)
309    last_name = models.CharField(_("last name"), max_length=150, blank=True)
310    email = models.EmailField(_("email address"), blank=True)
311    is_staff = models.BooleanField(
312        _("staff status"),
313        default=False,
314        help_text=_("Designates whether the user can log into this admin site."),
315    )
316    is_active = models.BooleanField(
317        _("active"),
318        default=True,
319        help_text=_(
320            "Designates whether this user should be treated as active. "
321            "Unselect this instead of deleting accounts."
322        ),
323    )
324    date_joined = models.DateTimeField(_("date joined"), default=timezone.now)
325
326    objects = UserManager()
327
328    EMAIL_FIELD = "email"
329    USERNAME_FIELD = "username"
330    REQUIRED_FIELDS = ["email"]
331
332    class Meta:
333        verbose_name = _("user")
334        verbose_name_plural = _("users")
335        abstract = True
336
337    def clean(self):
338        super().clean()
339        self.email = self.__class__.objects.normalize_email(self.email)
340
341    def get_full_name(self):
342        """
343        Return the first_name plus the last_name, with a space in between.
344        """
345        full_name = "%s %s" % (self.first_name, self.last_name)
346        return full_name.strip()
347
348    def get_short_name(self):
349        """Return the short name for the user."""
350        return self.first_name
351
352    def email_user(self, subject, message, from_email=None, **kwargs):
353        """Send an email to this user."""
354        send_mail(subject, message, from_email, [self.email], **kwargs)
355
356
357class User(AbstractUser):
358    """
359    Users within the Django authentication system are represented by this
360    model.
361
362    Username and password are required. Other fields are optional.
363    """
364
365    class Meta(AbstractUser.Meta):
366        swappable = "AUTH_USER_MODEL"
367
368
369class AnonymousUser:
370    id = None
371    pk = None
372    username = ""
373    is_staff = False
374    is_active = False
375    is_superuser = False
376    _groups = EmptyManager(Group)
377    _user_permissions = EmptyManager(Permission)
378
379    def __str__(self):
380        return "AnonymousUser"
381
382    def __eq__(self, other):
383        return isinstance(other, self.__class__)
384
385    def __hash__(self):
386        return 1  # instances always return the same hash value
387
388    def __int__(self):
389        raise TypeError(
390            "Cannot cast AnonymousUser to int. Are you trying to use it in place of User?"
391        )
392
393    def save(self):
394        raise NotImplementedError(
395            "Django doesn't provide a DB representation for AnonymousUser."
396        )
397
398    def delete(self):
399        raise NotImplementedError(
400            "Django doesn't provide a DB representation for AnonymousUser."
401        )
402
403    def set_password(self, raw_password):
404        raise NotImplementedError(
405            "Django doesn't provide a DB representation for AnonymousUser."
406        )
407
408    def check_password(self, raw_password):
409        raise NotImplementedError(
410            "Django doesn't provide a DB representation for AnonymousUser."
411        )
412
413    @property
414    def groups(self):
415        return self._groups
416
417    @property
418    def user_permissions(self):
419        return self._user_permissions
420
421    def get_group_permissions(self, obj=None):
422        return set()
423
424    def get_all_permissions(self, obj=None):
425        return _user_get_all_permissions(self, obj=obj)
426
427    def has_perm(self, perm, obj=None):
428        return _user_has_perm(self, perm, obj=obj)
429
430    def has_perms(self, perm_list, obj=None):
431        return all(self.has_perm(perm, obj) for perm in perm_list)
432
433    def has_module_perms(self, module):
434        return _user_has_module_perms(self, module)
435
436    @property
437    def is_anonymous(self):
438        return True
439
440    @property
441    def is_authenticated(self):
442        return False
443
444    def get_username(self):
445        return self.username

Module Python django/contrib/auth/base_user.py

  1"""
  2This module allows importing AbstractBaseUser even when django.contrib.auth is
  3not in INSTALLED_APPS.
  4"""
  5import unicodedata
  6
  7from django.contrib.auth import password_validation
  8from django.contrib.auth.hashers import check_password
  9from django.contrib.auth.hashers import is_password_usable
 10from django.contrib.auth.hashers import make_password
 11from django.db import models
 12from django.utils.crypto import get_random_string
 13from django.utils.crypto import salted_hmac
 14from django.utils.translation import gettext_lazy as _
 15
 16
 17class BaseUserManager(models.Manager):
 18    @classmethod
 19    def normalize_email(cls, email):
 20        """
 21        Normalize the email address by lowercasing the domain part of it.
 22        """
 23        email = email or ""
 24        try:
 25            email_name, domain_part = email.strip().rsplit("@", 1)
 26        except ValueError:
 27            pass
 28        else:
 29            email = email_name + "@" + domain_part.lower()
 30        return email
 31
 32    def make_random_password(
 33        self,
 34        length=10,
 35        allowed_chars="abcdefghjkmnpqrstuvwxyz" "ABCDEFGHJKLMNPQRSTUVWXYZ" "23456789",
 36    ):
 37        """
 38        Generate a random password with the given length and given
 39        allowed_chars. The default value of allowed_chars does not have "I" or
 40        "O" or letters and digits that look similar -- just to avoid confusion.
 41        """
 42        return get_random_string(length, allowed_chars)
 43
 44    def get_by_natural_key(self, username):
 45        return self.get(**{self.model.USERNAME_FIELD: username})
 46
 47
 48class AbstractBaseUser(models.Model):
 49    password = models.CharField(_("password"), max_length=128)
 50    last_login = models.DateTimeField(_("last login"), blank=True, null=True)
 51
 52    is_active = True
 53
 54    REQUIRED_FIELDS = []
 55
 56    # Stores the raw password if set_password() is called so that it can
 57    # be passed to password_changed() after the model is saved.
 58    _password = None
 59
 60    class Meta:
 61        abstract = True
 62
 63    def __str__(self):
 64        return self.get_username()
 65
 66    def save(self, *args, **kwargs):
 67        super().save(*args, **kwargs)
 68        if self._password is not None:
 69            password_validation.password_changed(self._password, self)
 70            self._password = None
 71
 72    def get_username(self):
 73        """Return the username for this User."""
 74        return getattr(self, self.USERNAME_FIELD)
 75
 76    def clean(self):
 77        setattr(self, self.USERNAME_FIELD, self.normalize_username(self.get_username()))
 78
 79    def natural_key(self):
 80        return (self.get_username(),)
 81
 82    @property
 83    def is_anonymous(self):
 84        """
 85        Always return False. This is a way of comparing User objects to
 86        anonymous users.
 87        """
 88        return False
 89
 90    @property
 91    def is_authenticated(self):
 92        """
 93        Always return True. This is a way to tell if the user has been
 94        authenticated in templates.
 95        """
 96        return True
 97
 98    def set_password(self, raw_password):
 99        self.password = make_password(raw_password)
100        self._password = raw_password
101
102    def check_password(self, raw_password):
103        """
104        Return a boolean of whether the raw_password was correct. Handles
105        hashing formats behind the scenes.
106        """
107
108        def setter(raw_password):
109            self.set_password(raw_password)
110            # Password hash upgrades shouldn't be considered password changes.
111            self._password = None
112            self.save(update_fields=["password"])
113
114        return check_password(raw_password, self.password, setter)
115
116    def set_unusable_password(self):
117        # Set a value that will never be a valid hash
118        self.password = make_password(None)
119
120    def has_usable_password(self):
121        """
122        Return False if set_unusable_password() has been called for this user.
123        """
124        return is_password_usable(self.password)
125
126    def get_session_auth_hash(self):
127        """
128        Return an HMAC of the password field.
129        """
130        key_salt = "django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash"
131        return salted_hmac(key_salt, self.password).hexdigest()
132
133    @classmethod
134    def get_email_field_name(cls):
135        try:
136            return cls.EMAIL_FIELD
137        except AttributeError:
138            return "email"
139
140    @classmethod
141    def normalize_username(cls, username):
142        return (
143            unicodedata.normalize("NFKC", username)
144            if isinstance(username, str)
145            else username
146        )

Module Python django/contrib/auth/mixins.py

  1from django.conf import settings
  2from django.contrib.auth import REDIRECT_FIELD_NAME
  3from django.contrib.auth.views import redirect_to_login
  4from django.core.exceptions import ImproperlyConfigured
  5from django.core.exceptions import PermissionDenied
  6
  7
  8class AccessMixin:
  9    """
 10    Abstract CBV mixin that gives access mixins the same customizable
 11    functionality.
 12    """
 13
 14    login_url = None
 15    permission_denied_message = ""
 16    raise_exception = False
 17    redirect_field_name = REDIRECT_FIELD_NAME
 18
 19    def get_login_url(self):
 20        """
 21        Override this method to override the login_url attribute.
 22        """
 23        login_url = self.login_url or settings.LOGIN_URL
 24        if not login_url:
 25            raise ImproperlyConfigured(
 26                "{0} is missing the login_url attribute. Define {0}.login_url, settings.LOGIN_URL, or override "
 27                "{0}.get_login_url().".format(self.__class__.__name__)
 28            )
 29        return str(login_url)
 30
 31    def get_permission_denied_message(self):
 32        """
 33        Override this method to override the permission_denied_message attribute.
 34        """
 35        return self.permission_denied_message
 36
 37    def get_redirect_field_name(self):
 38        """
 39        Override this method to override the redirect_field_name attribute.
 40        """
 41        return self.redirect_field_name
 42
 43    def handle_no_permission(self):
 44        if self.raise_exception or self.request.user.is_authenticated:
 45            raise PermissionDenied(self.get_permission_denied_message())
 46        return redirect_to_login(
 47            self.request.get_full_path(),
 48            self.get_login_url(),
 49            self.get_redirect_field_name(),
 50        )
 51
 52
 53class LoginRequiredMixin(AccessMixin):
 54    """Verify that the current user is authenticated."""
 55
 56    def dispatch(self, request, *args, **kwargs):
 57        if not request.user.is_authenticated:
 58            return self.handle_no_permission()
 59        return super().dispatch(request, *args, **kwargs)
 60
 61
 62class PermissionRequiredMixin(AccessMixin):
 63    """Verify that the current user has all specified permissions."""
 64
 65    permission_required = None
 66
 67    def get_permission_required(self):
 68        """
 69        Override this method to override the permission_required attribute.
 70        Must return an iterable.
 71        """
 72        if self.permission_required is None:
 73            raise ImproperlyConfigured(
 74                "{0} is missing the permission_required attribute. Define {0}.permission_required, or override "
 75                "{0}.get_permission_required().".format(self.__class__.__name__)
 76            )
 77        if isinstance(self.permission_required, str):
 78            perms = (self.permission_required,)
 79        else:
 80            perms = self.permission_required
 81        return perms
 82
 83    def has_permission(self):
 84        """
 85        Override this method to customize the way permissions are checked.
 86        """
 87        perms = self.get_permission_required()
 88        return self.request.user.has_perms(perms)
 89
 90    def dispatch(self, request, *args, **kwargs):
 91        if not self.has_permission():
 92            return self.handle_no_permission()
 93        return super().dispatch(request, *args, **kwargs)
 94
 95
 96class UserPassesTestMixin(AccessMixin):
 97    """
 98    Deny a request with a permission error if the test_func() method returns
 99    False.
100    """
101
102    def test_func(self):
103        raise NotImplementedError(
104            "{0} is missing the implementation of the test_func() method.".format(
105                self.__class__.__name__
106            )
107        )
108
109    def get_test_func(self):
110        """
111        Override this method to use a different test_func method.
112        """
113        return self.test_func
114
115    def dispatch(self, request, *args, **kwargs):
116        user_test_result = self.get_test_func()()
117        if not user_test_result:
118            return self.handle_no_permission()
119        return super().dispatch(request, *args, **kwargs)

Module Python django/contrib/auth/urls.py

 1# The views used below are normally mapped in django.contrib.admin.urls.py
 2# This URLs file is used to provide a reliable view deployment for test purposes.
 3# It is also provided as a convenience to those who want to deploy these URLs
 4# elsewhere.
 5from django.contrib.auth import views
 6from django.urls import path
 7
 8urlpatterns = [
 9    path("login/", views.LoginView.as_view(), name="login"),
10    path("logout/", views.LogoutView.as_view(), name="logout"),
11    path(
12        "password_change/", views.PasswordChangeView.as_view(), name="password_change"
13    ),
14    path(
15        "password_change/done/",
16        views.PasswordChangeDoneView.as_view(),
17        name="password_change_done",
18    ),
19    path("password_reset/", views.PasswordResetView.as_view(), name="password_reset"),
20    path(
21        "password_reset/done/",
22        views.PasswordResetDoneView.as_view(),
23        name="password_reset_done",
24    ),
25    path(
26        "reset/<uidb64>/<token>/",
27        views.PasswordResetConfirmView.as_view(),
28        name="password_reset_confirm",
29    ),
30    path(
31        "reset/done/",
32        views.PasswordResetCompleteView.as_view(),
33        name="password_reset_complete",
34    ),
35]

Module Python django/contrib/auth/decorators.py

 1from functools import wraps
 2from urllib.parse import urlparse
 3
 4from django.conf import settings
 5from django.contrib.auth import REDIRECT_FIELD_NAME
 6from django.core.exceptions import PermissionDenied
 7from django.shortcuts import resolve_url
 8
 9
10def user_passes_test(
11    test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME
12):
13    """
14    Decorator for views that checks that the user passes the given test,
15    redirecting to the log-in page if necessary. The test should be a callable
16    that takes the user object and returns True if the user passes.
17    """
18
19    def decorator(view_func):
20        @wraps(view_func)
21        def _wrapped_view(request, *args, **kwargs):
22            if test_func(request.user):
23                return view_func(request, *args, **kwargs)
24            path = request.build_absolute_uri()
25            resolved_login_url = resolve_url(login_url or settings.LOGIN_URL)
26            # If the login url is the same scheme and net location then just
27            # use the path as the "next" url.
28            login_scheme, login_netloc = urlparse(resolved_login_url)[:2]
29            current_scheme, current_netloc = urlparse(path)[:2]
30            if (not login_scheme or login_scheme == current_scheme) and (
31                not login_netloc or login_netloc == current_netloc
32            ):
33                path = request.get_full_path()
34            from django.contrib.auth.views import redirect_to_login
35
36            return redirect_to_login(path, resolved_login_url, redirect_field_name)
37
38        return _wrapped_view
39
40    return decorator
41
42
43def login_required(
44    function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None
45):
46    """
47    Decorator for views that checks that the user is logged in, redirecting
48    to the log-in page if necessary.
49    """
50    actual_decorator = user_passes_test(
51        lambda u: u.is_authenticated,
52        login_url=login_url,
53        redirect_field_name=redirect_field_name,
54    )
55    if function:
56        return actual_decorator(function)
57    return actual_decorator
58
59
60def permission_required(perm, login_url=None, raise_exception=False):
61    """
62    Decorator for views that checks whether a user has a particular permission
63    enabled, redirecting to the log-in page if necessary.
64    If the raise_exception parameter is given the PermissionDenied exception
65    is raised.
66    """
67
68    def check_perms(user):
69        if isinstance(perm, str):
70            perms = (perm,)
71        else:
72            perms = perm
73        # First check if the user has the permission (even anon users)
74        if user.has_perms(perms):
75            return True
76        # In case the 403 handler should be called raise the exception
77        if raise_exception:
78            raise PermissionDenied
79        # As the last resort, show the login form
80        return False
81
82    return user_passes_test(check_perms, login_url=login_url)

Module Python django/contrib/auth/context_processors.py

 1# PermWrapper and PermLookupDict proxy the permissions system into objects that
 2# the template system can understand.
 3
 4
 5class PermLookupDict:
 6    def __init__(self, user, app_label):
 7        self.user, self.app_label = user, app_label
 8
 9    def __repr__(self):
10        return str(self.user.get_all_permissions())
11
12    def __getitem__(self, perm_name):
13        return self.user.has_perm("%s.%s" % (self.app_label, perm_name))
14
15    def __iter__(self):
16        # To fix 'item in perms.someapp' and __getitem__ interaction we need to
17        # define __iter__. See #18979 for details.
18        raise TypeError("PermLookupDict is not iterable.")
19
20    def __bool__(self):
21        return self.user.has_module_perms(self.app_label)
22
23
24class PermWrapper:
25    def __init__(self, user):
26        self.user = user
27
28    def __getitem__(self, app_label):
29        return PermLookupDict(self.user, app_label)
30
31    def __iter__(self):
32        # I am large, I contain multitudes.
33        raise TypeError("PermWrapper is not iterable.")
34
35    def __contains__(self, perm_name):
36        """
37        Lookup by "someapp" or "someapp.someperm" in perms.
38        """
39        if "." not in perm_name:
40            # The name refers to module.
41            return bool(self[perm_name])
42        app_label, perm_name = perm_name.split(".", 1)
43        return self[app_label][perm_name]
44
45
46def auth(request):
47    """
48    Return context variables required by apps that use Django's authentication
49    system.
50
51    If there is no 'user' attribute in the request, use AnonymousUser (from
52    django.contrib.auth).
53    """
54    if hasattr(request, "user"):
55        user = request.user
56    else:
57        from django.contrib.auth.models import AnonymousUser
58
59        user = AnonymousUser()
60
61    return {"user": user, "perms": PermWrapper(user)}