You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by as...@apache.org on 2022/04/25 11:26:46 UTC
[airflow] branch main updated: Fix dag_id extraction for dag level access checks in web ui (#23015)
This is an automated email from the ASF dual-hosted git repository.
ash 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 dd623016ae Fix dag_id extraction for dag level access checks in web ui (#23015)
dd623016ae is described below
commit dd623016aececfa7e0644e7da901902a7a629f44
Author: npodewitz <10...@users.noreply.github.com>
AuthorDate: Mon Apr 25 13:26:34 2022 +0200
Fix dag_id extraction for dag level access checks in web ui (#23015)
Properly extract dag_id from post form or json body for dag level access
permissions.
Added test case for dag level access.
Fixed test_success_fail_for_read_only_task_instance_access to succeed
due to the right reasons.
---
airflow/www/auth.py | 5 ++-
tests/www/views/test_views_acl.py | 82 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 85 insertions(+), 2 deletions(-)
diff --git a/airflow/www/auth.py b/airflow/www/auth.py
index cbb9582526..9d40c00a5c 100644
--- a/airflow/www/auth.py
+++ b/airflow/www/auth.py
@@ -36,7 +36,10 @@ def has_access(permissions: Optional[Sequence[Tuple[str, str]]] = None) -> Calla
appbuilder = current_app.appbuilder
- if appbuilder.sm.check_authorization(permissions, request.args.get('dag_id', None)):
+ dag_id = (
+ request.args.get("dag_id") or request.form.get("dag_id") or (request.json or {}).get("dag_id")
+ )
+ if appbuilder.sm.check_authorization(permissions, dag_id):
return func(*args, **kwargs)
elif not g.user.is_anonymous and not g.user.perms:
return (
diff --git a/tests/www/views/test_views_acl.py b/tests/www/views/test_views_acl.py
index a37d384539..85c787f492 100644
--- a/tests/www/views/test_views_acl.py
+++ b/tests/www/views/test_views_acl.py
@@ -736,6 +736,7 @@ def user_only_dags_tis(acl_app):
username="user_only_dags_tis",
role_name="role_only_dags_tis",
permissions=[
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_WEBSITE),
(permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG),
(permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK_INSTANCE),
],
@@ -756,7 +757,7 @@ def test_success_fail_for_read_only_task_instance_access(client_only_dags_tis):
form = dict(
task_id="run_this_last",
dag_id="example_bash_operator",
- execution_date=DEFAULT_DATE,
+ dag_run_id=DEFAULT_RUN_ID,
upstream="false",
downstream="false",
future="false",
@@ -844,3 +845,82 @@ def client_anonymous(acl_app):
def test_no_roles_permissions(request, client, url, status_code, expected_content):
resp = request.getfixturevalue(client).get(url, follow_redirects=True)
check_content_in_response(expected_content, resp, status_code)
+
+
+@pytest.fixture(scope="module")
+def user_dag_level_access_with_ti_edit(acl_app):
+ with create_user_scope(
+ acl_app,
+ username="user_dag_level_access_with_ti_edit",
+ role_name="role_dag_level_access_with_ti_edit",
+ permissions=[
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_WEBSITE),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK_INSTANCE),
+ (permissions.ACTION_CAN_EDIT, permissions.RESOURCE_TASK_INSTANCE),
+ (permissions.ACTION_CAN_EDIT, permissions.resource_name_for_dag("example_bash_operator")),
+ ],
+ ) as user:
+ yield user
+
+
+@pytest.fixture()
+def client_dag_level_access_with_ti_edit(acl_app, user_dag_level_access_with_ti_edit):
+ return client_with_login(
+ acl_app,
+ username="user_dag_level_access_with_ti_edit",
+ password="user_dag_level_access_with_ti_edit",
+ )
+
+
+def test_success_edit_ti_with_dag_level_access_only(client_dag_level_access_with_ti_edit):
+ form = dict(
+ task_id="run_this_last",
+ dag_id="example_bash_operator",
+ dag_run_id=DEFAULT_RUN_ID,
+ upstream="false",
+ downstream="false",
+ future="false",
+ past="false",
+ )
+ resp = client_dag_level_access_with_ti_edit.post('/success', data=form, follow_redirects=True)
+ check_content_in_response('Marked success on 1 task instances', resp)
+
+
+@pytest.fixture(scope="module")
+def user_ti_edit_without_dag_level_access(acl_app):
+ with create_user_scope(
+ acl_app,
+ username="user_ti_edit_without_dag_level_access",
+ role_name="role_ti_edit_without_dag_level_access",
+ permissions=[
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_WEBSITE),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK_INSTANCE),
+ (permissions.ACTION_CAN_EDIT, permissions.RESOURCE_TASK_INSTANCE),
+ ],
+ ) as user:
+ yield user
+
+
+@pytest.fixture()
+def client_ti_edit_without_dag_level_access(acl_app, user_ti_edit_without_dag_level_access):
+ return client_with_login(
+ acl_app,
+ username="user_ti_edit_without_dag_level_access",
+ password="user_ti_edit_without_dag_level_access",
+ )
+
+
+def test_failure_edit_ti_without_dag_level_access(client_ti_edit_without_dag_level_access):
+ form = dict(
+ task_id="run_this_last",
+ dag_id="example_bash_operator",
+ dag_run_id=DEFAULT_RUN_ID,
+ upstream="false",
+ downstream="false",
+ future="false",
+ past="false",
+ )
+ resp = client_ti_edit_without_dag_level_access.post('/success', data=form, follow_redirects=True)
+ check_content_not_in_response('Marked success on 1 task instances', resp)