apache / apache/airflow

Misleading authentication error during login for auth manager's with redirect auth flows

Open
#63,521 1 comment 0 reactions 0 assignees View on GitHub
area:auth area:core area:webserver kind:bug needs-triage
Dominant language
Python
Stars
46.9k
Forks
17.8k
Avg merge
2d 9h
Merged PRs (30d)
472

Description

### Apache Airflow version

Other Airflow 3 version (please specify below)

### If "Other Airflow 3 version" selected, which one?

3.1.7

### What happened?

We are using a custom auth manager implementation. When a client first accesses the web UI without having been authenticated, they see the "Error Unauthorized" landing page for about 1-2 seconds, before their authentication flow is completed. Since we are using a custom auth manager, we are not able to leverage recent fixes that were specifically scoped to the FAB auth manager (such as [this fix](https://github.com/apache/airflow/pull/61287/changes)).

We are _not_ using the FAB auth manager, or any subclasses thereof, but the bug described here is similar in nature to the ones described in these 2 FAB auth manager issues: https://github.com/apache/airflow/issues/57981 https://github.com/apache/airflow/issues/55612

Our auth manager's `login` route handler initiates a sequence of redirects, which ultimately return to another route handler managed by our auth manager, which issues the Airflow access token from the user credentials issued from the redirect flow.

TL;DR, the bug is as follows:
1. Unauthenticated client accesses the Airflow web UI at `base url`
2. Airflow core redirects the unauthenticated client to `/auth_mgr/login`
3. Route handler for `/auth_mgr/login` redirects client to internal auth flow, with an eventual callback to `/auth_mgr/airflow_token_from_creds`
4. `/auth_mgr/airflow_token_from_creds` handler sets the cookie and redirects the user to whatever their initial url was they requested in step 1.

For the duration of steps 1-4, the "Error Unauthorized" landing page is displayed, but that page should not be appearing while the authN flow is in progress.

### What you think should happen instead?

The "Error Unauthorized" landing page is displayed while a client is actively in the authentication flow, but that page should not be appearing while the authN flow is in progress. There should be some solution that prevents this race condition for all auth managers, not just the [recent FAB auth manager fix](https://github.com/apache/airflow/pull/61287/changes).

Possibly this is just a missing detail in the custom auth manager documentation. If that is the case, then there needs to be some details on how to prevent this aberrant behavior, particularly how to do it with FastAPI-based auth managers (the linked FAB fix pertains to flask).

### How to reproduce

```python
from time import sleep
from urllib.parse import urljoin

from airflow.configuration import conf
from airflow.api_fastapi.auth.managers.base_auth_manager import BaseAuthManager, COOKIE_NAME_JWT_TOKEN
from airflow.api_fastapi.auth.managers.models.base_user import BaseUser
from airflow.api_fastapi.app import (
AUTH_MANAGER_FASTAPI_APP_PREFIX,
)
from airflow.api_fastapi.common.router import AirflowRouter
from fastapi import FastAPI
from fastapi.responses import RedirectResponse

BASE_URL = conf.get("api", "base_url", fallback="/")

class FakeUser(BaseUser):

def get_id(self):
return "1"

def get_name(self):
return "Dummy"

class FakeAuthManager(BaseAuthManager[FakeUser]):
def get_fastapi_app(self):
router = AirflowRouter()

@router.get("/login")
def my_login(request: Request, next: str | None = None) -> RedirectResponse:

return RedirectResponse(url=f"http://foo/get-my-internal-creds?redirect={BASE_URL}/auth/airflow_token_from_creds")

@router.get("/airflow_token_from_creds")
def airflow_token_from_creds(request: Request) -> RedirectResponse:
airflow_token = _airflow_token_from_internal_creds(
request.cookies.get("internal-creds-cookie-name")
)
response = RedirectResponse(url=next if next is not None else BASE_URL, status_code=307)
response.set_cookie(
key=COOKIE_NAME_JWT_TOKEN,
value=airflow_token,
max_age=86400,
)
return response

app = FastAPI()
app.include_router(router)
return app

def get_url_login(self, **kwargs):
return urljoin(BASE_URL, f"{AUTH_MANAGER_FASTAPI_APP_PREFIX}/login")

# Assume all auth manager `is_authorized_*` methods just return `True` ....
```

### Operating System

Ubuntu 22.04.5 LTS

### Versions of Apache Airflow Providers

Pertains to Airflow core, version 3.1.7 (observed in all version since 3.0.0).

### Deployment

Official Apache Airflow Helm Chart

### Deployment details

_No response_

### Anything else?

_No response_

### Are you willing to submit PR?

- [ ] Yes I am willing to submit a PR!

### Code of Conduct

- [x] I agree to follow this project's [Code of Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.