This is an automated email from the ASF dual-hosted git repository.

vincbeck pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new ff17dc6790d Keycloak auth manager. Handle invalid resource (#51461)
ff17dc6790d is described below

commit ff17dc6790d113c053f4a57845a9ea95b06f056a
Author: Vincent <[email protected]>
AuthorDate: Fri Jun 6 10:16:20 2025 -0400

    Keycloak auth manager. Handle invalid resource (#51461)
---
 .../keycloak/auth_manager/keycloak_auth_manager.py | 12 +++++
 .../auth_manager/test_keycloak_auth_manager.py     | 53 +++++++++++++++++++++-
 2 files changed, 64 insertions(+), 1 deletion(-)

diff --git 
a/providers/keycloak/src/airflow/providers/keycloak/auth_manager/keycloak_auth_manager.py
 
b/providers/keycloak/src/airflow/providers/keycloak/auth_manager/keycloak_auth_manager.py
index 9857e8d1fd2..d4416ab78ef 100644
--- 
a/providers/keycloak/src/airflow/providers/keycloak/auth_manager/keycloak_auth_manager.py
+++ 
b/providers/keycloak/src/airflow/providers/keycloak/auth_manager/keycloak_auth_manager.py
@@ -16,6 +16,8 @@
 # under the License.
 from __future__ import annotations
 
+import json
+import logging
 from typing import TYPE_CHECKING, Any
 from urllib.parse import urljoin
 
@@ -45,6 +47,8 @@ if TYPE_CHECKING:
     )
     from airflow.api_fastapi.common.types import MenuItem
 
+log = logging.getLogger(__name__)
+
 
 class KeycloakAuthManager(BaseAuthManager[KeycloakAuthManagerUser]):
     """
@@ -246,6 +250,14 @@ class 
KeycloakAuthManager(BaseAuthManager[KeycloakAuthManagerUser]):
             return True
         if resp.status_code == 403:
             return False
+        if resp.status_code == 400:
+            error = json.loads(resp.text)
+            if error.get("error") == "invalid_resource":
+                log.debug(error["error_description"])
+                return False
+            raise AirflowException(
+                f"Request not recognized by Keycloak. {error.get('error')}. 
{error.get('error_description')}"
+            )
         raise AirflowException(f"Unexpected error: {resp.status_code} - 
{resp.text}")
 
     @staticmethod
diff --git 
a/providers/keycloak/tests/unit/keycloak/auth_manager/test_keycloak_auth_manager.py
 
b/providers/keycloak/tests/unit/keycloak/auth_manager/test_keycloak_auth_manager.py
index f9de61de79a..e397044b86b 100644
--- 
a/providers/keycloak/tests/unit/keycloak/auth_manager/test_keycloak_auth_manager.py
+++ 
b/providers/keycloak/tests/unit/keycloak/auth_manager/test_keycloak_auth_manager.py
@@ -16,6 +16,7 @@
 # under the License.
 from __future__ import annotations
 
+import json
 from unittest.mock import Mock, call, patch
 
 import pytest
@@ -204,9 +205,59 @@ class TestKeycloakAuthManager:
         resp.status_code = 500
         mock_requests.post.return_value = resp
 
-        with pytest.raises(AirflowException):
+        with pytest.raises(AirflowException) as e:
             getattr(auth_manager, function)(method="GET", user=user)
 
+        assert "Unexpected error" in str(e.value)
+
+    @pytest.mark.parametrize(
+        "function",
+        [
+            "is_authorized_configuration",
+            "is_authorized_connection",
+            "is_authorized_backfill",
+            "is_authorized_asset",
+            "is_authorized_asset_alias",
+            "is_authorized_variable",
+            "is_authorized_pool",
+        ],
+    )
+    
@patch("airflow.providers.keycloak.auth_manager.keycloak_auth_manager.requests")
+    def test_is_authorized_invalid_resource(self, mock_requests, function, 
auth_manager, user):
+        resp = Mock()
+        resp.status_code = 400
+        resp.text = json.dumps(
+            {"error": "invalid_resource", "error_description": "Resource with 
id [Pool] does not exist."}
+        )
+        mock_requests.post.return_value = resp
+
+        result = getattr(auth_manager, function)(method="GET", user=user)
+        assert result is False
+
+    @pytest.mark.parametrize(
+        "function",
+        [
+            "is_authorized_configuration",
+            "is_authorized_connection",
+            "is_authorized_backfill",
+            "is_authorized_asset",
+            "is_authorized_asset_alias",
+            "is_authorized_variable",
+            "is_authorized_pool",
+        ],
+    )
+    
@patch("airflow.providers.keycloak.auth_manager.keycloak_auth_manager.requests")
+    def test_is_authorized_invalid_request(self, mock_requests, function, 
auth_manager, user):
+        resp = Mock()
+        resp.status_code = 400
+        resp.text = json.dumps({"error": "invalid_scope", "error_description": 
"Invalid scopes: GET"})
+        mock_requests.post.return_value = resp
+
+        with pytest.raises(AirflowException) as e:
+            getattr(auth_manager, function)(method="GET", user=user)
+
+        assert "Request not recognized by Keycloak. invalid_scope. Invalid 
scopes: GET" in str(e.value)
+
     @pytest.mark.parametrize(
         "status_code_type, status_code_resource, expected_one_call, 
expected_two_calls",
         [

Reply via email to