diff --git a/docs/release-notes/changelog.rst b/docs/release-notes/changelog.rst index 03fefbd852..3865bef110 100644 --- a/docs/release-notes/changelog.rst +++ b/docs/release-notes/changelog.rst @@ -3,6 +3,275 @@ 2.x Changelog ============= +.. changelog:: 2.11.0 + :date: 2024-08-27 + + .. change:: Use PyJWT instead of python-jose + :type: feature + :pr: 3684 + + The functionality in :mod:`litestar.security.jwt` is now backed by + `PyJWT `_ instead of + `python-jose `_, due to the unclear + maintenance status of the latter. + + .. change:: DTO: Introduce ``forbid_unknown_fields`` config + :type: feature + :pr: 3690 + + Add a new config option to :class:`~litestar.dto.config.DTOConfig`: + :attr:`~litestar.dto.config.DTOConfig.forbid_unknown_fields` + When set to ``True``, a validation error response will be returned if the source + data contains fields not defined on the model. + + .. change:: DTO: Support ``extra="forbid"`` model config for ``PydanticDTO`` + :type: feature + :pr: 3691 + + For Pydantic models with `extra="forbid" `_ + in their configuration: + + .. tab-set:: + + .. tab-item:: Pydantic 2 + + .. code-block:: python + + class User(BaseModel): + model_config = ConfigDict(extra='ignore') + name: str + + .. tab-item:: Pydantic 1 + + .. code-block:: python + + class User(BaseModel): + class Config: + extra = "ignore" + name: str + + :attr:`~litestar.dto.config.DTOConfig.forbid_unknown_fields` will be set to ``True`` by default. + + .. note:: + It's still possible to override this configuration at the DTO level + + + To facilitate this feature, :meth:`~litestar.dto.base_dto.AbstractDTO.get_config_for_model_type` + has been added to :class:`~litestar.dto.base_dto.AbstractDTO`, allowing the + customization of the base config defined on the DTO factory for a specific model + type. It will be called on DTO factory initialization, and receives the concrete + DTO model type along side the :class:`~litestar.dto.config.DTOConfig` defined + on the base DTO, which it can alter and return a new version to be used within + the DTO instance. + + .. change:: Custom JWT payload classes + :type: feature + :pr: 3692 + + Support extending the default :class:`~litestar.security.jwt.Token` class used + by the JWT backends decode the payload into. + + - Add new ``token_cls`` field on the JWT auth config classes + - Add new ``token_cls`` parameter to JWT auth middlewares + - Switch to using msgspec to convert the JWT payload into instances of the token + class + + .. code-block:: python + + import dataclasses + import secrets + from typing import Any, Dict + + from litestar import Litestar, Request, get + from litestar.connection import ASGIConnection + from litestar.security.jwt import JWTAuth, Token + + @dataclasses.dataclass + class CustomToken(Token): + token_flag: bool = False + + @dataclasses.dataclass + class User: + id: str + + async def retrieve_user_handler(token: CustomToken, connection: ASGIConnection) -> User: + return User(id=token.sub) + + TOKEN_SECRET = secrets.token_hex() + + jwt_auth = JWTAuth[User]( + token_secret=TOKEN_SECRET, + retrieve_user_handler=retrieve_user_handler, + token_cls=CustomToken, + ) + + @get("/") + def handler(request: Request[User, CustomToken, Any]) -> Dict[str, Any]: + return {"id": request.user.id, "token_flag": request.auth.token_flag} + + + .. change:: Extended JWT configuration options + :type: feature + :pr: 3695 + + **New JWT backend fields** + + - :attr:`~litestar.security.jwt.JWTAuth.accepted_audiences` + - :attr:`~litestar.security.jwt.JWTAuth.accepted_issuers` + - :attr:`~litestar.security.jwt.JWTAuth.require_claims` + - :attr:`~litestar.security.jwt.JWTAuth.verify_expiry` + - :attr:`~litestar.security.jwt.JWTAuth.verify_not_before` + - :attr:`~litestar.security.jwt.JWTAuth.strict_audience` + + **New JWT middleware parameters** + + - :paramref:`~litestar.security.jwt.JWTAuthenticationMiddleware.token_audience` + - :paramref:`~litestar.security.jwt.JWTAuthenticationMiddleware.token_issuer` + - :paramref:`~litestar.security.jwt.JWTAuthenticationMiddleware.require_claims` + - :paramref:`~litestar.security.jwt.JWTAuthenticationMiddleware.verify_expiry` + - :paramref:`~litestar.security.jwt.JWTAuthenticationMiddleware.verify_not_before` + - :paramref:`~litestar.security.jwt.JWTAuthenticationMiddleware.strict_audience` + + **New ``Token.decode`` parameters** + + - :paramref:`~litestar.security.jwt.Token.decode.audience` + - :paramref:`~litestar.security.jwt.Token.decode.issuer` + - :paramref:`~litestar.security.jwt.Token.decode.require_claims` + - :paramref:`~litestar.security.jwt.Token.decode.verify_exp` + - :paramref:`~litestar.security.jwt.Token.decode.verify_nbf` + - :paramref:`~litestar.security.jwt.Token.decode.strict_audience` + + **Other changes** + + :meth`Token.decode_payload <~litestar.security.jwt.Token.decode_payload>` has + been added to make customization of payload decoding / verification easier + without having to re-implement the functionality of the base class method. + + .. seealso:: + :doc:`/usage/security/jwt` + + .. change:: Warn about greedy exclude patterns in middlewares + :type: feature + :pr: 3700 + + Raise a warning when a middlewares ``exclude`` pattern greedily matches all + paths. + + .. code-block:: python + + from litestar.middlewares + + class MyMiddleware(AbstractMiddleware): + exclude = ["/", "/home"] + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + await self.app(scope, receive, send) + + Middleware like this would silently be disabled for every route, since the + exclude pattern ``/`` matches all paths. If a configuration like this is + detected, a warning will now be raised at application startup. + + .. change:: RFC 9457 *Problem Details* plugin + :type: feature + :pr: 3323 + :issue: 3199 + + Add a plugin to support `RFC 9457 `_ + *Problem Details* responses for error response. + + :class:`~litestar.plugins.problem_details.ProblemDetailsPlugin` enables to + selectively or collectively turn responses with an error status code into + *Problem Detail* responses. + + .. seealso:: + :doc:`/usage/plugins/problem_details` + + .. change:: Fix creation of ``FormMultiDict`` in ``Request.form`` to properly handle multi-keys + :type: bugfix + :pr: 3639 + :issue: 3627 + + Fix https://github.com/litestar-org/litestar/issues/3627 by properly handling + the creation of :class:`~litestar.datastructures.FormMultiDict` where multiple + values are given for a single key, to make + :meth:`~litestar.connection.Request.form` match the behaviour of receiving form + data via the ``data`` kwarg inside a route handler. + + **Before** + + .. code-block:: python + + @post("/") + async def handler(request: Request) -> Any: + return (await request.form()).getall("foo") + + with create_test_client(handler) as client: + print(client.post("/", data={"foo": ["1", "2"]}).json()) # [["1", "2"]] + + **After** + + .. code-block:: python + + @post("/") + async def handler(request: Request) -> Any: + return (await request.form()).getall("foo") + + with create_test_client(handler) as client: + print(client.post("/", data={"foo": ["1", "2"]}).json()) # ["1", "2"] + + .. change:: DTO: Fix inconsistent use of strict decoding mode + :type: bugfix + :pr: 3685 + + Fix inconsistent usage of msgspec's ``strict`` mode in the base DTO backend. + + ``strict=False`` was being used when transferring from builtins, while + ``strict=True`` was used transferring from raw data, causing an unwanted + discrepancy in behaviour. + + .. change:: Use path template for prometheus metrics + :type: bugfix + :pr: 3687 + + Changed previous 1-by-1 replacement logic for + ``PrometheusMiddleware.group_path=true`` with a more robust and slightly faster + solution. + + .. change:: Ensure OpenTelemetry captures exceptions in the outermost application layers + :type: bugfix + :pr: 3689 + :issue: 3663 + + A bug was fixed that resulted in exception occurring in the outermost + application layer not being captured under the current request span, which led + to incomplete traces. + + .. change:: Fix CSRFMiddleware sometimes setting cookies for excluded paths + :type: bugfix + :pr: 3698 + :issue: 3688 + + Fix a bug that would cause :class:`~litestar.middleware.csrf.CSRFMiddleware` to + set a cookie (which would not be used subsequently) on routes it had been + excluded from via a path pattern. + + .. change:: Make override behaviour consistent between ``signature_namespace`` and ``signature_types`` + :type: bugfix + :pr: 3696 + :issue: 3681 + + Ensure that adding signature types to ``signature_namespace`` and + ``signature_types`` behaves the same way when a name was already present in the + namespace. + + Both will now issue a warning if a name is being overwritten with a different + type. If a name is registered again for the same type, no warning will be given. + + .. note:: + + You can disable this warning globally by setting + ``LITESTAR_WARN_SIGNATURE_NAMESPACE_OVERRIDE=0`` in your environment + .. changelog:: 2.10.0 :date: 2024-07-26 diff --git a/pyproject.toml b/pyproject.toml index 31dcc870c0..223e941780 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,7 +60,7 @@ maintainers = [ name = "litestar" readme = "README.md" requires-python = ">=3.8,<4.0" -version = "2.10.0" +version = "2.11.0" [project.urls] Blog = "https://blog.litestar.dev"