Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@
from fastapi import HTTPException, Request, status
from fastapi.responses import RedirectResponse

from airflow.api_fastapi.auth.managers.base_auth_manager import COOKIE_NAME_JWT_TOKEN
from airflow.api_fastapi.common.router import AirflowRouter
from airflow.api_fastapi.core_api.openapi.exceptions import create_openapi_http_exception_doc
from airflow.api_fastapi.core_api.security import AuthManagerDep, is_safe_url
from airflow.configuration import conf

auth_router = AirflowRouter(tags=["Login"], prefix="/auth")

Expand All @@ -47,11 +49,18 @@ def login(request: Request, auth_manager: AuthManagerDep, next: None | str = Non
"/logout",
responses=create_openapi_http_exception_doc([status.HTTP_307_TEMPORARY_REDIRECT]),
)
def logout(auth_manager: AuthManagerDep, next: None | str = None) -> RedirectResponse:
def logout(request: Request, auth_manager: AuthManagerDep, next: None | str = None) -> RedirectResponse:
"""Logout the user."""
logout_url = auth_manager.get_url_logout()
if logout_url:
return RedirectResponse(logout_url)

if not logout_url:
logout_url = auth_manager.get_url_login()
secure = request.base_url.scheme == "https" or bool(conf.get("api", "ssl_cert", fallback=""))
response = RedirectResponse(auth_manager.get_url_login())
response.delete_cookie(
key=COOKIE_NAME_JWT_TOKEN,
secure=secure,
httponly=True,
)

return RedirectResponse(logout_url)
return response
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ const LogoutModal: React.FC<LogoutModalProps> = ({ isOpen, onClose }) => {
onConfirm={() => {
const logoutPath = getRedirectPath("api/v2/auth/logout");

document.cookie = "_token=; Path=/; Max-Age=-99999999;";
globalThis.location.replace(logoutPath);
}}
onOpenChange={onClose}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

import pytest

from airflow.api_fastapi.auth.managers.base_auth_manager import COOKIE_NAME_JWT_TOKEN

from tests_common.test_utils.config import conf_vars

AUTH_MANAGER_LOGIN_URL = "http://some_login_url"
Expand Down Expand Up @@ -74,22 +76,27 @@ def test_should_respond_400(self, test_client, params):

class TestLogout(TestAuthEndpoint):
@pytest.mark.parametrize(
"mock_logout_url, expected_redirection",
"mock_logout_url, expected_redirection, delete_cookies",
[
# logout_url is None, should redirect to the login page directly.
(None, AUTH_MANAGER_LOGIN_URL),
(None, AUTH_MANAGER_LOGIN_URL, True),
# logout_url is defined, should redirect to the logout_url.
("http://localhost/auth/some_logout_url", "http://localhost/auth/some_logout_url"),
("http://localhost/auth/some_logout_url", "http://localhost/auth/some_logout_url", False),
],
)
def test_should_respond_307(
self,
test_client,
mock_logout_url,
expected_redirection,
delete_cookies,
):
test_client.app.state.auth_manager.get_url_logout.return_value = mock_logout_url
response = test_client.get("/auth/logout", follow_redirects=False)

assert response.status_code == 307
assert response.headers["location"] == expected_redirection

if delete_cookies:
cookies = response.headers.get_list("set-cookie")
assert any(f"{COOKIE_NAME_JWT_TOKEN}=" in c for c in cookies)
Loading