Skip to content

Authentication middleware IndexError on instance method  #1334

Description

@LarsStegman

Checklist

  • The bug is reproducible against the latest release and/or master.
  • There are no similar issues or pull requests to fix it yet.

Describe the bug

We are using a wrapper around FastAPI which makes it possible to create routes on classes with endpoints on the methods. This makes it easier to manage dependency injection among others.

When we add authentication middleware to our application, the authenticated endpoints fail due to IndexError: tuple index out of range.

This error occurs at authentication.py:60

request = kwargs.get("request", args[idx] if args else None)

We use the following definitions:

@router.endpoint("/")
class Main:   
    @router.get("/")
    async def hello(self):
        return {"greeting": "Hello unknown!"}
 
    @requires("admin")
    @router.get("/authorized")
    async def authorized(self, request: Request):
        return {"greeting": f"Hi {request.user.display_name()}, you're authorized, so welcome!"}

We have created the class decorator for endpoint ourselves.

I looked in the debugger and both args and kwargs contain values. args contains self for the instance method and kwargs contains request. This causes the if args check to pass, which means args[idx] will cause an IndexError. This can be fixed by adding an additional check:

request = kwargs.get("request", args[idx] if args and idx < len(args) else None)

To reproduce

It is not easily possible to create a reproduction example due to our custom wrapper around FastAPI. Implementing this fix does fix the problem for us though.

To reproduce:

Details
import typing

from fastapi import APIRouter, FastAPI
from starlette.authentication import AuthCredentials, AuthenticationBackend, requires, SimpleUser, BaseUser
from starlette.requests import HTTPConnection, Request
from starlette.middleware.authentication import AuthenticationMiddleware


class AuthBackend(AuthenticationBackend):

    async def authenticate(self, conn: HTTPConnection) -> typing.Optional[typing.Tuple["AuthCredentials", "BaseUser"]]:
        return AuthCredentials(["TheScope"]), SimpleUser("TheUser)")


app = FastAPI()
app.add_middleware(AuthenticationMiddleware, backend=AuthBackend())


class Main:
    @requires("TheScope")
    def some_route(self, request: Request):
        return {'hello': 'world'}


main = Main()
router = APIRouter()
router.add_api_route('/', main.some_route, methods=['GET'])

app.include_router(router)

# Finally, call GET '/'

Expected behavior

When a request is made to an authentication endpoint the request either returns "forbidden" when the authentication is not valid or returns the required response.

Actual behavior

The authentication wrapper requires fails when the request is made. This happens due to an IndexError when idx >= len(args).

Debugging material

Traceback:

Details
ERROR:uvicorn.error:Exception in ASGI application
Traceback (most recent call last):
  File "C:\Users\<path-to-virtual-env>\lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 394, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "C:\Users\<path-to-virtual-env>\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 45, in __call__
    return await self.app(scope, receive, send)
  File "C:\Users\<path-to-virtual-env>\lib\site-packages\allseas_api\api.py", line 63, in __call__
    await self._fast_api.__call__(scope, receive, send)
  File "C:\Users\<path-to-virtual-env>\lib\site-packages\fastapi\applications.py", line 179, in __call__
    await super().__call__(scope, receive, send)
  File "C:\Users\<path-to-virtual-env>\lib\site-packages\starlette\applications.py", line 111, in __call__
    await self.middleware_stack(scope, receive, send)
  File "C:\Users\<path-to-virtual-env>\lib\site-packages\starlette\middleware\errors.py", line 181, in __call__
    raise exc from None
  File "C:\Users\<path-to-virtual-env>\lib\site-packages\starlette\middleware\errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "C:\Users\<path-to-virtual-env>\lib\site-packages\starlette\middleware\gzip.py", line 18, in __call__
    await responder(scope, receive, send)
  File "C:\Users\<path-to-virtual-env>\lib\site-packages\starlette\middleware\gzip.py", line 35, in __call__
    await self.app(scope, receive, self.send_with_gzip)
  File "C:\Users\<path-to-virtual-env>\lib\site-packages\starlette\middleware\authentication.py", line 48, in __call__
    await self.app(scope, receive, send)
  File "C:\Users\<path-to-virtual-env>\lib\site-packages\starlette\exceptions.py", line 82, in __call__
    raise exc from None
  File "C:\Users\<path-to-virtual-env>\lib\site-packages\starlette\exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "C:\Users\<path-to-virtual-env>\lib\site-packages\starlette\routing.py", line 566, in __call__
    await route.handle(scope, receive, send)
  File "C:\Users\<path-to-virtual-env>\lib\site-packages\starlette\routing.py", line 227, in handle
    await self.app(scope, receive, send)
  File "C:\Users\<path-to-virtual-env>\lib\site-packages\starlette\routing.py", line 41, in app
    response = await func(request)
  File "C:\Users\<path-to-virtual-env>\lib\site-packages\fastapi\routing.py", line 182, in app
    raw_response = await run_endpoint_function(
  File "C:\Users\<path-to-virtual-env>\lib\site-packages\fastapi\routing.py", line 133, in run_endpoint_function
    return await dependant.call(**values)
  File "C:\Users\<path-to-virtual-env>\lib\site-packages\starlette\authentication.py", line 60, in async_wrapper
    request = kwargs.get("request", args[idx] if args else None)
IndexError: tuple index out of range

Environment

  • OS: Windows
  • Python version: 3.9.7
  • Starlette version: 0.17.0

Additional context

We need to add bearer token authentication to our endpoints. Our endpoints are methods on class instances.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions