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 b79b7f44381 Add `LIST` scope in Keycloak auth manager (#54998)
b79b7f44381 is described below
commit b79b7f4438196b032bacbbbd38232040a51318ba
Author: Vincent <[email protected]>
AuthorDate: Thu Aug 28 08:33:12 2025 -0400
Add `LIST` scope in Keycloak auth manager (#54998)
---
.../providers/keycloak/auth_manager/cli/commands.py | 6 +++---
.../keycloak/auth_manager/keycloak_auth_manager.py | 2 ++
.../auth_manager/test_keycloak_auth_manager.py | 18 +++++++++---------
3 files changed, 14 insertions(+), 12 deletions(-)
diff --git
a/providers/keycloak/src/airflow/providers/keycloak/auth_manager/cli/commands.py
b/providers/keycloak/src/airflow/providers/keycloak/auth_manager/cli/commands.py
index 59bd60ef5ba..d19693b81cc 100644
---
a/providers/keycloak/src/airflow/providers/keycloak/auth_manager/cli/commands.py
+++
b/providers/keycloak/src/airflow/providers/keycloak/auth_manager/cli/commands.py
@@ -114,7 +114,7 @@ def _get_client_uuid(args):
def _create_scopes(client: KeycloakAdmin, client_uuid: str):
scopes = [{"name": method} for method in get_args(ResourceMethod)]
- scopes.append({"name": "MENU"})
+ scopes.extend([{"name": "MENU"}, {"name": "LIST"}])
for scope in scopes:
client.create_client_authz_scopes(client_id=client_uuid, payload=scope)
@@ -126,7 +126,7 @@ def _create_resources(client: KeycloakAdmin, client_uuid:
str):
scopes = [
{"id": scope["id"], "name": scope["name"]}
for scope in all_scopes
- if scope["name"] in ["GET", "POST", "PUT", "DELETE"]
+ if scope["name"] in ["GET", "POST", "PUT", "DELETE", "LIST"]
]
for resource in KeycloakResource:
@@ -166,7 +166,7 @@ def _create_permissions(client: KeycloakAdmin, client_uuid:
str):
def _create_read_only_permission(client: KeycloakAdmin, client_uuid: str):
all_scopes = client.get_client_authz_scopes(client_uuid)
- scopes = [scope["id"] for scope in all_scopes if scope["name"] in ["GET",
"MENU"]]
+ scopes = [scope["id"] for scope in all_scopes if scope["name"] in ["GET",
"MENU", "LIST"]]
payload = {
"name": "ReadOnly",
"type": "scope",
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 d91b5030bda..8fdaa0b03e9 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
@@ -286,6 +286,8 @@ class
KeycloakAuthManager(BaseAuthManager[KeycloakAuthManagerUser]):
context_attributes = prune_dict(attributes or {})
if resource_id:
context_attributes[RESOURCE_ID_ATTRIBUTE_NAME] = resource_id
+ elif method == "GET":
+ method = "LIST"
resp = requests.post(
self._get_token_url(server_url, realm),
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 bec66aef210..2e7478b2991 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
@@ -112,7 +112,7 @@ class TestKeycloakAuthManager:
"Configuration#GET",
{RESOURCE_ID_ATTRIBUTE_NAME: "test"},
],
- ["is_authorized_configuration", "GET", None, "Configuration#GET",
None],
+ ["is_authorized_configuration", "GET", None, "Configuration#LIST",
None],
[
"is_authorized_configuration",
"PUT",
@@ -127,7 +127,7 @@ class TestKeycloakAuthManager:
"Connection#DELETE",
{RESOURCE_ID_ATTRIBUTE_NAME: "test"},
],
- ["is_authorized_connection", "GET", None, "Connection#GET", {}],
+ ["is_authorized_connection", "GET", None, "Connection#LIST", {}],
[
"is_authorized_backfill",
"POST",
@@ -135,7 +135,7 @@ class TestKeycloakAuthManager:
"Backfill#POST",
{RESOURCE_ID_ATTRIBUTE_NAME: "1"},
],
- ["is_authorized_backfill", "GET", None, "Backfill#GET", {}],
+ ["is_authorized_backfill", "GET", None, "Backfill#LIST", {}],
[
"is_authorized_asset",
"GET",
@@ -143,7 +143,7 @@ class TestKeycloakAuthManager:
"Asset#GET",
{RESOURCE_ID_ATTRIBUTE_NAME: "test"},
],
- ["is_authorized_asset", "GET", None, "Asset#GET", {}],
+ ["is_authorized_asset", "GET", None, "Asset#LIST", {}],
[
"is_authorized_asset_alias",
"GET",
@@ -151,7 +151,7 @@ class TestKeycloakAuthManager:
"AssetAlias#GET",
{RESOURCE_ID_ATTRIBUTE_NAME: "test"},
],
- ["is_authorized_asset_alias", "GET", None, "AssetAlias#GET", {}],
+ ["is_authorized_asset_alias", "GET", None, "AssetAlias#LIST", {}],
[
"is_authorized_variable",
"PUT",
@@ -159,7 +159,7 @@ class TestKeycloakAuthManager:
"Variable#PUT",
{RESOURCE_ID_ATTRIBUTE_NAME: "test"},
],
- ["is_authorized_variable", "GET", None, "Variable#GET", {}],
+ ["is_authorized_variable", "GET", None, "Variable#LIST", {}],
[
"is_authorized_pool",
"POST",
@@ -167,7 +167,7 @@ class TestKeycloakAuthManager:
"Pool#POST",
{RESOURCE_ID_ATTRIBUTE_NAME: "test"},
],
- ["is_authorized_pool", "GET", None, "Pool#GET", {}],
+ ["is_authorized_pool", "GET", None, "Pool#LIST", {}],
],
)
@pytest.mark.parametrize(
@@ -257,7 +257,7 @@ class TestKeycloakAuthManager:
"GET",
None,
None,
- "Dag#GET",
+ "Dag#LIST",
{},
],
[
@@ -278,7 +278,7 @@ class TestKeycloakAuthManager:
"GET",
DagAccessEntity.TASK_INSTANCE,
None,
- "Dag#GET",
+ "Dag#LIST",
{"dag_entity": "TASK_INSTANCE"},
],
],