diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py index 67eac083e793..7a0ccf42de32 100644 --- a/django/contrib/admin/widgets.py +++ b/django/contrib/admin/widgets.py @@ -28,6 +28,8 @@ class FilteredSelectMultiple(forms.SelectMultiple): catalog has been loaded in the page """ + use_fieldset = True + class Media: js = [ "admin/js/core.js", @@ -300,7 +302,7 @@ def __init__( self.can_view_related = supported and can_view_related # To check if the related object is registered with this AdminSite. self.admin_site = admin_site - self.use_fieldset = True + self.use_fieldset = widget.use_fieldset def __deepcopy__(self, memo): obj = copy.copy(self) diff --git a/django/contrib/auth/__init__.py b/django/contrib/auth/__init__.py index 2702c38aa4d3..21e6dc43d633 100644 --- a/django/contrib/auth/__init__.py +++ b/django/contrib/auth/__init__.py @@ -205,6 +205,8 @@ async def alogin(request, user, backend=None): await request.session.aset(SESSION_KEY, user._meta.pk.value_to_string(user)) await request.session.aset(BACKEND_SESSION_KEY, backend) await request.session.aset(HASH_SESSION_KEY, session_auth_hash) + if hasattr(request, "user"): + request.user = user if hasattr(request, "auser"): async def auser(): @@ -244,13 +246,21 @@ async def alogout(request): user = None await user_logged_out.asend(sender=user.__class__, request=request, user=user) await request.session.aflush() - if hasattr(request, "auser"): + + has_user = hasattr(request, "user") + has_auser = hasattr(request, "auser") + if has_user or has_auser: from django.contrib.auth.models import AnonymousUser - async def auser(): - return AnonymousUser() + anon = AnonymousUser() + if has_user: + request.user = anon + if has_auser: - request.auser = auser + async def auser(): + return anon + + request.auser = auser def get_user_model(): diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 7a4cf843c1b1..8be560856b06 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -13,7 +13,7 @@ import sys import warnings from collections import Counter, namedtuple -from collections.abc import Iterator, Mapping +from collections.abc import Iterable, Iterator, Mapping from itertools import chain, count, product from string import ascii_uppercase @@ -1638,7 +1638,17 @@ def build_filter( ): lookup_class = targets[0].get_lookup("isnull") col = self._get_col(targets[0], join_info.targets[0], alias) - clause.add(lookup_class(col, False), AND) + # Use OR + IS NULL when RHS `in` values include None. + if ( + lookup_type == "in" + # Check containers (not strings or bytes). + and isinstance(condition.rhs, Iterable) + and not isinstance(condition.rhs, (str, bytes)) + and any(v is None for v in condition.rhs) + ): + clause.add(lookup_class(col, True), OR) + else: + clause.add(lookup_class(col, False), AND) # If someval is a nullable column, someval IS NOT NULL is # added. if isinstance(value, Col) and self.is_nullable(value.target): diff --git a/docs/howto/auth-remote-user.txt b/docs/howto/auth-remote-user.txt index 533f460e4ac4..fe48bb3dc86a 100644 --- a/docs/howto/auth-remote-user.txt +++ b/docs/howto/auth-remote-user.txt @@ -99,19 +99,26 @@ instead of :class:`django.contrib.auth.middleware.RemoteUserMiddleware`:: .. warning:: - Be very careful if using a ``RemoteUserMiddleware`` subclass with a custom - HTTP header. You must be sure that your front-end web server always sets or - strips that header based on the appropriate authentication checks, never - permitting an end-user to submit a fake (or "spoofed") header value. Since - the HTTP headers ``X-Auth-User`` and ``X-Auth_User`` (for example) both - normalize to the ``HTTP_X_AUTH_USER`` key in ``request.META``, you must - also check that your web server doesn't allow a spoofed header using + ``RemoteUserMiddleware`` must not be deployed in configurations where a + client can supply the header. You must be sure that your web server or + reverse proxy always sets or strips that header based on the appropriate + authentication checks, never permitting an end user to submit a fake (or + "spoofed") header value. In particular, ASGI deployments cannot be exposed + directly to the internet (that is, without a reverse proxy) when using this + middleware. + + Since the HTTP headers ``X-Auth-User`` and ``X-Auth_User`` (for example) + both normalize to the ``HTTP_X_AUTH_USER`` key in ``request.META``, you + must also check that your web server doesn't allow a spoofed header using underscores in place of dashes. - This warning doesn't apply to ``RemoteUserMiddleware`` in its default - configuration with ``header = 'REMOTE_USER'``, since a key that doesn't - start with ``HTTP_`` in ``request.META`` can only be set by your WSGI - or ASGI server, not directly from an HTTP request header. + Under WSGI, this warning doesn't apply to ``RemoteUserMiddleware`` in its + default configuration with ``header = "REMOTE_USER"``, since a key that + doesn't start with ``HTTP_`` in ``request.META`` can only be set by your + WSGI server, not directly from an HTTP request header. This warning *does* + apply by default on ASGI, because in the async path, the middleware + prepends ``HTTP_`` to the defined header name before looking it up in + ``request.META``. If you need more control, you can create your own authentication backend that inherits from :class:`~django.contrib.auth.backends.RemoteUserBackend` and diff --git a/docs/internals/security.txt b/docs/internals/security.txt index 5214bf0704a4..3dd811fcd0ee 100644 --- a/docs/internals/security.txt +++ b/docs/internals/security.txt @@ -43,6 +43,39 @@ the industry-standard 90 days. Confirmed vulnerabilities with a .. _our public Trac instance: https://code.djangoproject.com/query +.. _respecting-maintainer-time: + +Respecting maintainer time +-------------------------- + +Django's security team are volunteers. Please be mindful and respectful of +their time when submitting reports. Your initial report should give the team +enough to make a triage decision, no more. It should include: + +* A brief description of the issue and where in Django it occurs. + +* A minimal, working proof of concept (code snippet or reproduction steps). + +* The versions of Django and Python you tested against. + +* Optionally, a minimal patch with the mitigation for the issue. + +Please do not include severity scores (CVSS or otherwise), lengthy background +sections, multiple headers, or a determination of whether the issue constitutes +a vulnerability. The security team will make those assessments. Extensive +upfront analysis makes triage slower, not faster. If the team confirms the +issue is a valid vulnerability, they will follow up and welcome further detail +at that stage. + +If you have identified multiple potential issues, please wait for a triage +result on your initial report before submitting further ones. Exceptions can be +made for issues that are clearly and directly related to an already reported +finding. Feedback on an initial report is often relevant to subsequent ones, +and taking the time to read and incorporate it leads to better reports overall. + +The security team is not able to process large volumes of reports submitted in +a short period of time, and reports submitted in bulk may be put on hold. + Reporting guidelines -------------------- @@ -131,6 +164,12 @@ not been sanitized:: q = MyModel.objects.extra(select={"id": query}) return HttpResponse(q.values()) +Some HTTP headers must also be sanitized by a web server or fronting proxy +before they can be used, such as ``Remote-User`` and ``X-Forwarded-*``. For +instance, under ASGI, it is a deployment misconfiguration (rather than any flaw +in Django) for Django to be the direct HTTP endpoint when +:class:`~django.contrib.auth.middleware.RemoteUserMiddleware` is used. + Request headers and URLs must be under 8K bytes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/ref/middleware.txt b/docs/ref/middleware.txt index a9638cf36e5c..e53c51039354 100644 --- a/docs/ref/middleware.txt +++ b/docs/ref/middleware.txt @@ -576,13 +576,14 @@ Customize the login URL or field name for authenticated views with the .. class:: RemoteUserMiddleware Middleware for utilizing web server provided authentication. See - :doc:`/howto/auth-remote-user` for usage details. + :doc:`/howto/auth-remote-user` for usage details, including security + considerations. .. class:: PersistentRemoteUserMiddleware Middleware for utilizing web server provided authentication when enabled only on the login page. See :ref:`persistent-remote-user-middleware-howto` - for usage details. + for usage details, including security considerations. CSRF protection middleware -------------------------- diff --git a/docs/releases/6.0.4.txt b/docs/releases/6.0.4.txt index a32a49dc93e0..1967edacc840 100644 --- a/docs/releases/6.0.4.txt +++ b/docs/releases/6.0.4.txt @@ -10,4 +10,11 @@ issues with severity "low", and several bugs in 6.0.3. Bugfixes ======== -* ... +* Fixed a regression in Django 6.0 where :func:`~django.contrib.auth.alogin` + and :func:`~django.contrib.auth.alogout` did not respectively set or clear + ``request.user`` if it had already been materialized (e.g., by sync + middleware) (:ticket:`37017`). + +* Fixed a regression in Django 6.0 in admin forms where + ``RelatedFieldWidgetWrapper`` incorrectly wrapped all widgets in a + ``