Source code for falcon_auth2.backends.basic

import base64
from typing import Callable, Optional

from falcon import Request

from ..exc import BackendNotApplicable
from ..getter import AuthHeaderGetter, Getter
from ..utils import RequestAttributes, await_, check_getter
from .base import BaseAuthBackend


[docs]class BasicAuthBackend(BaseAuthBackend): """Implements the `'Basic' HTTP Authentication Scheme <https://tools.ietf.org/html/rfc7617>`_. Clients should authenticate by passing the credential in the format ``username:password`` encoded in ``base64`` in the ``Authorization`` HTTP header, prepending it with the type specified in the setting ``auth_header_type``. For example, the user ``"Aladdin"`` would provide his password, ``"open sesame"``, with the header:: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== Args: user_loader (Callable): A callable object that is called with the :class:`~RequestAttributes` object and the username and password credentials extracted from the request using the provided ``getter``. It should return the user identified by the request, or ``None`` if no user could be not found. When using falcon in async mode (asgi), this function may also be async. Note: An error will be raised if an async function is used when using falcon in sync mode (wsgi). Note: Exceptions raised in this callable are not handled directly, and are surfaced to falcon. Keyword Args: auth_header_type (string, optional): The type of authentication required in the ``Authorization`` header. This value is added to the ``challenges`` in case of errors. Defaults to ``"Basic"``. Note: When passing a custom getter this value is only used to generate the ``challenges``, since the getter will be used to obtain the credentials to authenticate. getter (Optional[Getter]): Getter used to extract the authentication information from the request. When using a custom getter, the returned value must be a ``base64`` encoded string with the credentials in the format ``username:password``. Defaults to :class:`~.AuthHeaderGetter` initialized with the provided ``auth_header_type``. """ def __init__( self, user_loader: Callable, *, auth_header_type: str = "Basic", getter: Optional[Getter] = None, ): super().__init__(user_loader, challenges=(auth_header_type,)) if getter: check_getter(getter) self.auth_header_type = auth_header_type self.getter = getter or AuthHeaderGetter(auth_header_type) def _extract_credentials(self, req: Request, is_async: bool): if is_async and not self.getter.async_calls_sync_load: auth_data = await_(self.getter.load_async(req, challenges=self.challenges)) else: auth_data = self.getter.load(req, challenges=self.challenges) try: auth_data = base64.b64decode(auth_data).decode("utf-8") username, password = auth_data.split(":", 1) except Exception: raise BackendNotApplicable( description="Invalid Authorization Header: Unable to decode credentials", challenges=self.challenges, ) return username, password
[docs] def authenticate(self, attributes: RequestAttributes) -> dict: "Authenticates the request and returns the authenticated user." username, password = self._extract_credentials(attributes[0], attributes[-1]) return {"user": self.load_user(attributes, username, password)}