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 2020/10/18 01:47:23 UTC
[airflow] branch master updated: Use permission constants (#11389)
This is an automated email from the ASF dual-hosted git repository.
ash pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/master by this push:
new 7285182 Use permission constants (#11389)
7285182 is described below
commit 728518224b9c6469c74b66d9d2b47b13de00fc8c
Author: James Timmins <ja...@astronomer.io>
AuthorDate: Sat Oct 17 18:46:11 2020 -0700
Use permission constants (#11389)
Use constants for permission resource and action names.
---
airflow/api_connexion/endpoints/config_endpoint.py | 3 +-
.../api_connexion/endpoints/connection_endpoint.py | 11 +++--
airflow/api_connexion/endpoints/dag_endpoint.py | 8 ++--
.../api_connexion/endpoints/dag_run_endpoint.py | 35 ++++++++++++--
.../api_connexion/endpoints/dag_source_endpoint.py | 4 +-
.../api_connexion/endpoints/event_log_endpoint.py | 5 +-
.../api_connexion/endpoints/extra_link_endpoint.py | 8 ++--
.../endpoints/import_error_endpoint.py | 5 +-
airflow/api_connexion/endpoints/log_endpoint.py | 6 ++-
airflow/api_connexion/endpoints/pool_endpoint.py | 11 +++--
airflow/api_connexion/endpoints/task_endpoint.py | 14 +++++-
.../endpoints/task_instance_endpoint.py | 30 ++++++++----
.../api_connexion/endpoints/variable_endpoint.py | 11 +++--
airflow/api_connexion/endpoints/xcom_endpoint.py | 16 +++----
airflow/api_connexion/security.py | 9 ++--
airflow/security/permissions.py | 12 +++++
airflow/www/decorators.py | 3 +-
airflow/www/security.py | 6 +--
airflow/www/views.py | 9 ++--
.../endpoints/test_config_endpoint.py | 6 ++-
.../endpoints/test_connection_endpoint.py | 9 ++--
tests/api_connexion/endpoints/test_dag_endpoint.py | 11 +++--
.../endpoints/test_dag_run_endpoint.py | 15 +++---
.../endpoints/test_dag_source_endpoint.py | 6 ++-
.../endpoints/test_event_log_endpoint.py | 6 ++-
.../endpoints/test_extra_link_endpoint.py | 8 ++--
.../endpoints/test_import_error_endpoint.py | 3 +-
tests/api_connexion/endpoints/test_log_endpoint.py | 6 +--
.../api_connexion/endpoints/test_pool_endpoint.py | 9 ++--
.../api_connexion/endpoints/test_task_endpoint.py | 6 +--
.../endpoints/test_task_instance_endpoint.py | 13 +++---
.../endpoints/test_variable_endpoint.py | 9 ++--
.../api_connexion/endpoints/test_xcom_endpoint.py | 17 ++++---
.../schemas/test_task_instance_schema.py | 5 +-
tests/cli/commands/test_sync_perm_command.py | 5 +-
tests/models/test_dag.py | 11 ++++-
tests/serialization/test_dag_serialization.py | 7 +--
tests/www/test_security.py | 53 ++++++++++++++++------
tests/www/test_views.py | 10 ++--
39 files changed, 277 insertions(+), 144 deletions(-)
diff --git a/airflow/api_connexion/endpoints/config_endpoint.py b/airflow/api_connexion/endpoints/config_endpoint.py
index ded1ec4..34ed1ac 100644
--- a/airflow/api_connexion/endpoints/config_endpoint.py
+++ b/airflow/api_connexion/endpoints/config_endpoint.py
@@ -20,6 +20,7 @@ from flask import Response, request
from airflow.api_connexion import security
from airflow.api_connexion.schemas.config_schema import Config, ConfigOption, ConfigSection, config_schema
from airflow.configuration import conf
+from airflow.security import permissions
from airflow.settings import json
LINE_SEP = '\n' # `\n` cannot appear in f-strings
@@ -61,7 +62,7 @@ def _config_to_json(config: Config) -> str:
return json.dumps(config_schema.dump(config), indent=4)
-@security.requires_access([("can_read", "Config")])
+@security.requires_access([(permissions.ACTION_CAN_READ, permissions.RESOURCE_CONFIG)])
def get_config() -> Response:
"""
Get current configuration.
diff --git a/airflow/api_connexion/endpoints/connection_endpoint.py b/airflow/api_connexion/endpoints/connection_endpoint.py
index d1bcfc7..5e7a4d8 100644
--- a/airflow/api_connexion/endpoints/connection_endpoint.py
+++ b/airflow/api_connexion/endpoints/connection_endpoint.py
@@ -30,10 +30,11 @@ from airflow.api_connexion.schemas.connection_schema import (
connection_schema,
)
from airflow.models import Connection
+from airflow.security import permissions
from airflow.utils.session import provide_session
-@security.requires_access([("can_delete", "Connection")])
+@security.requires_access([(permissions.ACTION_CAN_DELETE, permissions.RESOURCE_CONNECTION)])
@provide_session
def delete_connection(connection_id, session):
"""
@@ -49,7 +50,7 @@ def delete_connection(connection_id, session):
return NoContent, 204
-@security.requires_access([("can_read", "Connection")])
+@security.requires_access([(permissions.ACTION_CAN_READ, permissions.RESOURCE_CONNECTION)])
@provide_session
def get_connection(connection_id, session):
"""
@@ -64,7 +65,7 @@ def get_connection(connection_id, session):
return connection_collection_item_schema.dump(connection)
-@security.requires_access([("can_read", "Connection")])
+@security.requires_access([(permissions.ACTION_CAN_READ, permissions.RESOURCE_CONNECTION)])
@format_parameters({'limit': check_limit})
@provide_session
def get_connections(session, limit, offset=0):
@@ -79,7 +80,7 @@ def get_connections(session, limit, offset=0):
)
-@security.requires_access([("can_edit", "Connection")])
+@security.requires_access([(permissions.ACTION_CAN_EDIT, permissions.RESOURCE_CONNECTION)])
@provide_session
def patch_connection(connection_id, session, update_mask=None):
"""
@@ -115,7 +116,7 @@ def patch_connection(connection_id, session, update_mask=None):
return connection_schema.dump(connection)
-@security.requires_access([("can_create", "Connection")])
+@security.requires_access([(permissions.ACTION_CAN_CREATE, permissions.RESOURCE_CONNECTION)])
@provide_session
def post_connection(session):
"""
diff --git a/airflow/api_connexion/endpoints/dag_endpoint.py b/airflow/api_connexion/endpoints/dag_endpoint.py
index 33c3643..7ff69b8 100644
--- a/airflow/api_connexion/endpoints/dag_endpoint.py
+++ b/airflow/api_connexion/endpoints/dag_endpoint.py
@@ -32,7 +32,7 @@ from airflow.security import permissions
from airflow.utils.session import provide_session
-@security.requires_access([("can_read", permissions.RESOURCE_DAGS)])
+@security.requires_access([(permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS)])
@provide_session
def get_dag(dag_id, session):
"""
@@ -46,7 +46,7 @@ def get_dag(dag_id, session):
return dag_schema.dump(dag)
-@security.requires_access([("can_read", permissions.RESOURCE_DAGS)])
+@security.requires_access([(permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS)])
def get_dag_details(dag_id):
"""
Get details of DAG.
@@ -57,7 +57,7 @@ def get_dag_details(dag_id):
return dag_detail_schema.dump(dag)
-@security.requires_access([("can_read", permissions.RESOURCE_DAGS)])
+@security.requires_access([(permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS)])
@format_parameters({'limit': check_limit})
def get_dags(limit, offset=0):
"""
@@ -70,7 +70,7 @@ def get_dags(limit, offset=0):
return dags_collection_schema.dump(DAGCollection(dags=dags, total_entries=total_entries))
-@security.requires_access([("can_edit", permissions.RESOURCE_DAGS)])
+@security.requires_access([(permissions.ACTION_CAN_EDIT, permissions.RESOURCE_DAGS)])
@provide_session
def patch_dag(session, dag_id, update_mask=None):
"""
diff --git a/airflow/api_connexion/endpoints/dag_run_endpoint.py b/airflow/api_connexion/endpoints/dag_run_endpoint.py
index 2d3a297..81cc69d 100644
--- a/airflow/api_connexion/endpoints/dag_run_endpoint.py
+++ b/airflow/api_connexion/endpoints/dag_run_endpoint.py
@@ -33,7 +33,12 @@ from airflow.utils.session import provide_session
from airflow.utils.types import DagRunType
-@security.requires_access([("can_read", permissions.RESOURCE_DAGS), ("can_delete", "DagRun")])
+@security.requires_access(
+ [
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_DELETE, permissions.RESOURCE_DAG_RUN),
+ ]
+)
@provide_session
def delete_dag_run(dag_id, dag_run_id, session):
"""
@@ -44,7 +49,12 @@ def delete_dag_run(dag_id, dag_run_id, session):
return NoContent, 204
-@security.requires_access([("can_read", permissions.RESOURCE_DAGS), ("can_read", "DagRun")])
+@security.requires_access(
+ [
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ ]
+)
@provide_session
def get_dag_run(dag_id, dag_run_id, session):
"""
@@ -59,7 +69,12 @@ def get_dag_run(dag_id, dag_run_id, session):
return dagrun_schema.dump(dag_run)
-@security.requires_access([("can_read", permissions.RESOURCE_DAGS), ("can_read", "DagRun")])
+@security.requires_access(
+ [
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ ]
+)
@format_parameters(
{
'start_date_gte': format_datetime,
@@ -158,7 +173,12 @@ def _apply_date_filters_to_query(
return query
-@security.requires_access([("can_read", permissions.RESOURCE_DAGS), ("can_read", "DagRun")])
+@security.requires_access(
+ [
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ ]
+)
@provide_session
def get_dag_runs_batch(session):
"""
@@ -194,7 +214,12 @@ def get_dag_runs_batch(session):
return dagrun_collection_schema.dump(DAGRunCollection(dag_runs=dag_runs, total_entries=total_entries))
-@security.requires_access([("can_read", permissions.RESOURCE_DAGS), ("can_create", "DagRun")])
+@security.requires_access(
+ [
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_CREATE, permissions.RESOURCE_DAG_RUN),
+ ]
+)
@provide_session
def post_dag_run(dag_id, session):
"""
diff --git a/airflow/api_connexion/endpoints/dag_source_endpoint.py b/airflow/api_connexion/endpoints/dag_source_endpoint.py
index 1bc9cf6..04c6d61 100644
--- a/airflow/api_connexion/endpoints/dag_source_endpoint.py
+++ b/airflow/api_connexion/endpoints/dag_source_endpoint.py
@@ -23,11 +23,13 @@ from airflow.api_connexion import security
from airflow.api_connexion.exceptions import NotFound
from airflow.api_connexion.schemas.dag_source_schema import dag_source_schema
from airflow.models.dagcode import DagCode
+from airflow.security import permissions
+
log = logging.getLogger(__name__)
-@security.requires_access([("can_read", "DagCode")])
+@security.requires_access([(permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_CODE)])
def get_dag_source(file_token: str):
"""
Get source code using file token
diff --git a/airflow/api_connexion/endpoints/event_log_endpoint.py b/airflow/api_connexion/endpoints/event_log_endpoint.py
index 39ff692..a3ad53f 100644
--- a/airflow/api_connexion/endpoints/event_log_endpoint.py
+++ b/airflow/api_connexion/endpoints/event_log_endpoint.py
@@ -27,10 +27,11 @@ from airflow.api_connexion.schemas.event_log_schema import (
event_log_schema,
)
from airflow.models import Log
+from airflow.security import permissions
from airflow.utils.session import provide_session
-@security.requires_access([('can_read', 'Log')])
+@security.requires_access([(permissions.ACTION_CAN_READ, permissions.RESOURCE_LOG)])
@provide_session
def get_event_log(event_log_id, session):
"""
@@ -42,7 +43,7 @@ def get_event_log(event_log_id, session):
return event_log_schema.dump(event_log)
-@security.requires_access([('can_read', 'Log')])
+@security.requires_access([(permissions.ACTION_CAN_READ, permissions.RESOURCE_LOG)])
@format_parameters({'limit': check_limit})
@provide_session
def get_event_logs(session, limit, offset=None):
diff --git a/airflow/api_connexion/endpoints/extra_link_endpoint.py b/airflow/api_connexion/endpoints/extra_link_endpoint.py
index 4ec0554..b2151a8 100644
--- a/airflow/api_connexion/endpoints/extra_link_endpoint.py
+++ b/airflow/api_connexion/endpoints/extra_link_endpoint.py
@@ -29,10 +29,10 @@ from airflow.utils.session import provide_session
@security.requires_access(
[
- ('can_read', permissions.RESOURCE_DAGS),
- ('can_read', 'DagRun'),
- ('can_read', 'Task'),
- ('can_read', 'TaskInstance'),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK_INSTANCE),
]
)
@provide_session
diff --git a/airflow/api_connexion/endpoints/import_error_endpoint.py b/airflow/api_connexion/endpoints/import_error_endpoint.py
index 830576b..05b001f 100644
--- a/airflow/api_connexion/endpoints/import_error_endpoint.py
+++ b/airflow/api_connexion/endpoints/import_error_endpoint.py
@@ -26,10 +26,11 @@ from airflow.api_connexion.schemas.error_schema import (
import_error_schema,
)
from airflow.models.errors import ImportError # pylint: disable=redefined-builtin
+from airflow.security import permissions
from airflow.utils.session import provide_session
-@security.requires_access([('can_read', 'ImportError')])
+@security.requires_access([(permissions.ACTION_CAN_READ, permissions.RESOURCE_IMPORT_ERROR)])
@provide_session
def get_import_error(import_error_id, session):
"""
@@ -45,7 +46,7 @@ def get_import_error(import_error_id, session):
return import_error_schema.dump(error)
-@security.requires_access([('can_read', 'ImportError')])
+@security.requires_access([(permissions.ACTION_CAN_READ, permissions.RESOURCE_IMPORT_ERROR)])
@format_parameters({'limit': check_limit})
@provide_session
def get_import_errors(session, limit, offset=None):
diff --git a/airflow/api_connexion/endpoints/log_endpoint.py b/airflow/api_connexion/endpoints/log_endpoint.py
index 32d5396..4c32489 100644
--- a/airflow/api_connexion/endpoints/log_endpoint.py
+++ b/airflow/api_connexion/endpoints/log_endpoint.py
@@ -29,7 +29,11 @@ from airflow.utils.session import provide_session
@security.requires_access(
- [('can_read', permissions.RESOURCE_DAGS), ('can_read', 'DagRun'), ('can_read', 'Task')]
+ [
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK),
+ ]
)
@provide_session
def get_log(session, dag_id, dag_run_id, task_id, task_try_number, full_content=False, token=None):
diff --git a/airflow/api_connexion/endpoints/pool_endpoint.py b/airflow/api_connexion/endpoints/pool_endpoint.py
index 7033542..13ba32d 100644
--- a/airflow/api_connexion/endpoints/pool_endpoint.py
+++ b/airflow/api_connexion/endpoints/pool_endpoint.py
@@ -24,10 +24,11 @@ from airflow.api_connexion.exceptions import AlreadyExists, BadRequest, NotFound
from airflow.api_connexion.parameters import check_limit, format_parameters
from airflow.api_connexion.schemas.pool_schema import PoolCollection, pool_collection_schema, pool_schema
from airflow.models.pool import Pool
+from airflow.security import permissions
from airflow.utils.session import provide_session
-@security.requires_access([("can_delete", "Pool")])
+@security.requires_access([(permissions.ACTION_CAN_DELETE, permissions.RESOURCE_POOL)])
@provide_session
def delete_pool(pool_name: str, session):
"""
@@ -41,7 +42,7 @@ def delete_pool(pool_name: str, session):
return Response(status=204)
-@security.requires_access([("can_read", "Pool")])
+@security.requires_access([(permissions.ACTION_CAN_READ, permissions.RESOURCE_POOL)])
@provide_session
def get_pool(pool_name, session):
"""
@@ -53,7 +54,7 @@ def get_pool(pool_name, session):
return pool_schema.dump(obj)
-@security.requires_access([("can_read", "Pool")])
+@security.requires_access([(permissions.ACTION_CAN_READ, permissions.RESOURCE_POOL)])
@format_parameters({'limit': check_limit})
@provide_session
def get_pools(session, limit, offset=None):
@@ -65,7 +66,7 @@ def get_pools(session, limit, offset=None):
return pool_collection_schema.dump(PoolCollection(pools=pools, total_entries=total_entries))
-@security.requires_access([("can_edit", "Pool")])
+@security.requires_access([(permissions.ACTION_CAN_EDIT, permissions.RESOURCE_POOL)])
@provide_session
def patch_pool(pool_name, session, update_mask=None):
"""
@@ -116,7 +117,7 @@ def patch_pool(pool_name, session, update_mask=None):
return pool_schema.dump(pool)
-@security.requires_access([("can_create", "Pool")])
+@security.requires_access([(permissions.ACTION_CAN_CREATE, permissions.RESOURCE_POOL)])
@provide_session
def post_pool(session):
"""
diff --git a/airflow/api_connexion/endpoints/task_endpoint.py b/airflow/api_connexion/endpoints/task_endpoint.py
index d818ebb..36755db 100644
--- a/airflow/api_connexion/endpoints/task_endpoint.py
+++ b/airflow/api_connexion/endpoints/task_endpoint.py
@@ -24,7 +24,12 @@ from airflow.exceptions import TaskNotFound
from airflow.security import permissions
-@security.requires_access([("can_read", permissions.RESOURCE_DAGS), ("can_read", "Task")])
+@security.requires_access(
+ [
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK),
+ ]
+)
def get_task(dag_id, task_id):
"""
Get simplified representation of a task.
@@ -40,7 +45,12 @@ def get_task(dag_id, task_id):
return task_schema.dump(task)
-@security.requires_access([("can_read", permissions.RESOURCE_DAGS), ("can_read", "Task")])
+@security.requires_access(
+ [
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK),
+ ]
+)
def get_tasks(dag_id):
"""
Get tasks for DAG
diff --git a/airflow/api_connexion/endpoints/task_instance_endpoint.py b/airflow/api_connexion/endpoints/task_instance_endpoint.py
index b9ee25f..8ce0961 100644
--- a/airflow/api_connexion/endpoints/task_instance_endpoint.py
+++ b/airflow/api_connexion/endpoints/task_instance_endpoint.py
@@ -44,9 +44,9 @@ from airflow.utils.session import provide_session
@security.requires_access(
[
- ("can_read", permissions.RESOURCE_DAGS),
- ("can_read", "DagRun"),
- ("can_read", "Task"),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK),
]
)
@provide_session
@@ -102,9 +102,9 @@ def _apply_range_filter(query, key, value_range: Tuple[Any, Any]):
)
@security.requires_access(
[
- ("can_read", permissions.RESOURCE_DAGS),
- ("can_read", "DagRun"),
- ("can_read", "Task"),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK),
]
)
@provide_session
@@ -171,7 +171,11 @@ def get_task_instances(
@security.requires_access(
- [("can_read", permissions.RESOURCE_DAGS), ("can_read", "DagRun"), ("can_read", "Task")]
+ [
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK),
+ ]
)
@provide_session
def get_task_instances_batch(session=None):
@@ -227,7 +231,11 @@ def get_task_instances_batch(session=None):
@security.requires_access(
- [("can_read", permissions.RESOURCE_DAGS), ("can_read", "DagRun"), ("can_edit", "Task")]
+ [
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ (permissions.ACTION_CAN_EDIT, permissions.RESOURCE_TASK),
+ ]
)
@provide_session
def post_clear_task_instances(dag_id: str, session=None):
@@ -269,7 +277,11 @@ def post_clear_task_instances(dag_id: str, session=None):
@security.requires_access(
- [("can_read", permissions.RESOURCE_DAGS), ("can_read", "DagRun"), ("can_edit", "Task")]
+ [
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ (permissions.ACTION_CAN_EDIT, permissions.RESOURCE_TASK),
+ ]
)
@provide_session
def post_set_task_instances_state(dag_id, session):
diff --git a/airflow/api_connexion/endpoints/variable_endpoint.py b/airflow/api_connexion/endpoints/variable_endpoint.py
index e0ad2f1..b7e1bab 100644
--- a/airflow/api_connexion/endpoints/variable_endpoint.py
+++ b/airflow/api_connexion/endpoints/variable_endpoint.py
@@ -25,10 +25,11 @@ from airflow.api_connexion.exceptions import BadRequest, NotFound
from airflow.api_connexion.parameters import check_limit, format_parameters
from airflow.api_connexion.schemas.variable_schema import variable_collection_schema, variable_schema
from airflow.models import Variable
+from airflow.security import permissions
from airflow.utils.session import provide_session
-@security.requires_access([("can_delete", "Variable")])
+@security.requires_access([(permissions.ACTION_CAN_DELETE, permissions.RESOURCE_VARIABLE)])
def delete_variable(variable_key: str) -> Response:
"""
Delete variable
@@ -38,7 +39,7 @@ def delete_variable(variable_key: str) -> Response:
return Response(status=204)
-@security.requires_access([("can_read", "Variable")])
+@security.requires_access([(permissions.ACTION_CAN_READ, permissions.RESOURCE_VARIABLE)])
def get_variable(variable_key: str) -> Response:
"""
Get a variables by key
@@ -50,7 +51,7 @@ def get_variable(variable_key: str) -> Response:
return variable_schema.dump({"key": variable_key, "val": var})
-@security.requires_access([("can_read", "Variable")])
+@security.requires_access([(permissions.ACTION_CAN_READ, permissions.RESOURCE_VARIABLE)])
@format_parameters({'limit': check_limit})
@provide_session
def get_variables(session, limit: Optional[int], offset: Optional[int] = None) -> Response:
@@ -72,7 +73,7 @@ def get_variables(session, limit: Optional[int], offset: Optional[int] = None) -
)
-@security.requires_access([("can_edit", "Variable")])
+@security.requires_access([(permissions.ACTION_CAN_EDIT, permissions.RESOURCE_VARIABLE)])
def patch_variable(variable_key: str, update_mask: Optional[List[str]] = None) -> Response:
"""
Update a variable by key
@@ -95,7 +96,7 @@ def patch_variable(variable_key: str, update_mask: Optional[List[str]] = None) -
return Response(status=204)
-@security.requires_access([("can_create", "Variable")])
+@security.requires_access([(permissions.ACTION_CAN_CREATE, permissions.RESOURCE_VARIABLE)])
def post_variables() -> Response:
"""
Create a variable
diff --git a/airflow/api_connexion/endpoints/xcom_endpoint.py b/airflow/api_connexion/endpoints/xcom_endpoint.py
index 39dc503..b6608f5 100644
--- a/airflow/api_connexion/endpoints/xcom_endpoint.py
+++ b/airflow/api_connexion/endpoints/xcom_endpoint.py
@@ -37,10 +37,10 @@ from airflow.utils.session import provide_session
@security.requires_access(
[
- ("can_read", permissions.RESOURCE_DAGS),
- ("can_read", "DagRun"),
- ("can_read", "Task"),
- ("can_read", "XCom"),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_XCOM),
]
)
@format_parameters({'limit': check_limit})
@@ -78,10 +78,10 @@ def get_xcom_entries(
@security.requires_access(
[
- ("can_read", permissions.RESOURCE_DAGS),
- ("can_read", "DagRun"),
- ("can_read", "Task"),
- ("can_read", "XCom"),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_XCOM),
]
)
@provide_session
diff --git a/airflow/api_connexion/security.py b/airflow/api_connexion/security.py
index 373a700..271652a 100644
--- a/airflow/api_connexion/security.py
+++ b/airflow/api_connexion/security.py
@@ -20,7 +20,7 @@ from typing import Callable, Optional, Sequence, Tuple, TypeVar, cast
from flask import Response, current_app, g
-from airflow.security.permissions import RESOURCE_DAGS
+import airflow.security.permissions as perms
from airflow.api_connexion.exceptions import PermissionDenied, Unauthenticated
T = TypeVar("T", bound=Callable) # pylint: disable=invalid-name
@@ -42,7 +42,7 @@ def can_access_any_dags(action: str, dag_id: Optional[int] = None) -> bool:
return appbuilder.sm.has_access(action, appbuilder.sm.prefixed_dag_id(dag_id))
user = g.user
- if action == 'can_read':
+ if action == perms.ACTION_CAN_READ:
return any(appbuilder.sm.get_readable_dags(user))
return any(appbuilder.sm.get_editable_dags(user))
@@ -55,7 +55,10 @@ def check_authorization(
return
appbuilder = current_app.appbuilder
for permission in permissions:
- if permission in (('can_read', RESOURCE_DAGS), ('can_edit', RESOURCE_DAGS)):
+ if permission in (
+ (perms.ACTION_CAN_READ, perms.RESOURCE_DAGS),
+ (perms.ACTION_CAN_EDIT, perms.RESOURCE_DAGS),
+ ):
can_access_all_dags = appbuilder.sm.has_access(*permission)
if can_access_all_dags:
continue
diff --git a/airflow/security/permissions.py b/airflow/security/permissions.py
index 94d2cc2..747b6fe 100644
--- a/airflow/security/permissions.py
+++ b/airflow/security/permissions.py
@@ -18,6 +18,18 @@
# Resource Constants
RESOURCE_DAGS = 'Dags'
RESOURCE_DAG_PREFIX = 'DAG:'
+RESOURCE_CONFIG = 'Config'
+RESOURCE_CONNECTION = 'Connection'
+RESOURCE_DAG_CODE = 'DagCode'
+RESOURCE_DAG_RUN = 'DagRun'
+RESOURCE_IMPORT_ERROR = 'ImportError'
+RESOURCE_LOG = 'Log'
+RESOURCE_POOL = 'Pool'
+RESOURCE_TASK = 'Task'
+RESOURCE_TASK_INSTANCE = 'TaskInstance'
+RESOURCE_VARIABLE = "Variable"
+RESOURCE_WEBSITE = 'Website'
+RESOURCE_XCOM = 'XCom'
# Action Constants
ACTION_CAN_CREATE = 'can_create'
diff --git a/airflow/www/decorators.py b/airflow/www/decorators.py
index 4ee0af9..20a0ee7 100644
--- a/airflow/www/decorators.py
+++ b/airflow/www/decorators.py
@@ -25,6 +25,7 @@ import pendulum
from flask import after_this_request, flash, g, redirect, request, url_for
from airflow.models import Log
+from airflow.security import permissions
from airflow.utils.session import create_session
T = TypeVar("T", bound=Callable) # pylint: disable=invalid-name
@@ -112,7 +113,7 @@ def has_dag_access(**dag_kwargs) -> Callable[[T], T]:
@functools.wraps(f)
def wrapper(self, *args, **kwargs):
dag_id = request.values.get('dag_id')
- needs_edit_access = dag_kwargs.get('can_dag_edit', False)
+ needs_edit_access = dag_kwargs.get(permissions.DEPRECATED_ACTION_CAN_DAG_EDIT, False)
if needs_edit_access:
if self.appbuilder.sm.can_edit_dag(dag_id):
diff --git a/airflow/www/security.py b/airflow/www/security.py
index 9aa543e..816468d 100644
--- a/airflow/www/security.py
+++ b/airflow/www/security.py
@@ -54,7 +54,7 @@ class AirflowSecurityManager(SecurityManager, LoggingMixin):
'Airflow',
'DagModelView',
'Browse',
- 'Config',
+ permissions.RESOURCE_CONFIG,
'DAG Runs',
'DagRunModelView',
'Task Instances',
@@ -131,8 +131,8 @@ class AirflowSecurityManager(SecurityManager, LoggingMixin):
'can_run',
'can_trigger',
'can_add',
- 'can_edit',
- 'can_delete',
+ permissions.ACTION_CAN_EDIT,
+ permissions.ACTION_CAN_DELETE,
'can_failed',
'can_paused',
'can_refresh',
diff --git a/airflow/www/views.py b/airflow/www/views.py
index 345d705..2862af0 100644
--- a/airflow/www/views.py
+++ b/airflow/www/views.py
@@ -2440,7 +2440,7 @@ class XComModelView(AirflowModelView):
datamodel = AirflowModelView.CustomSQLAInterface(XCom)
- base_permissions = ['can_list', 'can_delete']
+ base_permissions = ['can_list', permissions.ACTION_CAN_DELETE]
search_columns = ['key', 'value', 'timestamp', 'execution_date', 'task_id', 'dag_id']
list_columns = ['key', 'value', 'timestamp', 'execution_date', 'task_id', 'dag_id']
@@ -2481,7 +2481,7 @@ class ConnectionModelView(AirflowModelView):
datamodel = AirflowModelView.CustomSQLAInterface(Connection) # noqa # type: ignore
- base_permissions = ['can_add', 'can_list', 'can_edit', 'can_delete']
+ base_permissions = ['can_add', 'can_list', permissions.ACTION_CAN_EDIT, permissions.ACTION_CAN_DELETE]
extra_fields = ['extra__jdbc__drv_path', 'extra__jdbc__drv_clsname',
'extra__google_cloud_platform__project',
@@ -2553,7 +2553,7 @@ class PoolModelView(AirflowModelView):
datamodel = AirflowModelView.CustomSQLAInterface(models.Pool) # noqa # type: ignore
- base_permissions = ['can_add', 'can_list', 'can_edit', 'can_delete']
+ base_permissions = ['can_add', 'can_list', permissions.ACTION_CAN_EDIT, permissions.ACTION_CAN_DELETE]
list_columns = ['pool', 'slots', 'running_slots', 'queued_slots']
add_columns = ['pool', 'slots', 'description']
@@ -2627,7 +2627,8 @@ class VariableModelView(AirflowModelView):
datamodel = AirflowModelView.CustomSQLAInterface(models.Variable) # noqa # type: ignore
- base_permissions = ['can_add', 'can_list', 'can_edit', 'can_delete', 'can_varimport']
+ base_permissions = ['can_add', 'can_list', permissions.ACTION_CAN_EDIT,
+ permissions.ACTION_CAN_DELETE, 'can_varimport']
list_columns = ['key', 'val', 'is_encrypted']
add_columns = ['key', 'val']
diff --git a/tests/api_connexion/endpoints/test_config_endpoint.py b/tests/api_connexion/endpoints/test_config_endpoint.py
index 81f896c..096bcb2 100644
--- a/tests/api_connexion/endpoints/test_config_endpoint.py
+++ b/tests/api_connexion/endpoints/test_config_endpoint.py
@@ -19,6 +19,7 @@ import textwrap
from mock import patch
+from airflow.security import permissions
from airflow.www import app
from tests.test_utils.api_connexion_utils import assert_401, create_user, delete_user
from tests.test_utils.config import conf_vars
@@ -41,7 +42,10 @@ class TestGetConfig:
with conf_vars({("api", "auth_backend"): "tests.test_utils.remote_user_api_auth_backend"}):
cls.app = app.create_app(testing=True) # type:ignore
create_user(
- cls.app, username="test", role_name="Test", permissions=[('can_read', 'Config')] # type: ignore
+ cls.app, # type:ignore
+ username="test",
+ role_name="Test",
+ permissions=[(permissions.ACTION_CAN_READ, permissions.RESOURCE_CONFIG)], # type: ignore
)
create_user(cls.app, username="test_no_permissions", role_name="TestNoPermissions") # type: ignore
diff --git a/tests/api_connexion/endpoints/test_connection_endpoint.py b/tests/api_connexion/endpoints/test_connection_endpoint.py
index 1242f7d..643a2c1 100644
--- a/tests/api_connexion/endpoints/test_connection_endpoint.py
+++ b/tests/api_connexion/endpoints/test_connection_endpoint.py
@@ -20,6 +20,7 @@ from parameterized import parameterized
from airflow.api_connexion.exceptions import EXCEPTIONS_LINK_MAP
from airflow.models import Connection
+from airflow.security import permissions
from airflow.utils.session import provide_session
from airflow.www import app
from tests.test_utils.api_connexion_utils import assert_401, create_user, delete_user
@@ -38,10 +39,10 @@ class TestConnectionEndpoint(unittest.TestCase):
username="test",
role_name="Test",
permissions=[
- ("can_create", "Connection"),
- ("can_read", "Connection"),
- ("can_edit", "Connection"),
- ("can_delete", "Connection"),
+ (permissions.ACTION_CAN_CREATE, permissions.RESOURCE_CONNECTION),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_CONNECTION),
+ (permissions.ACTION_CAN_EDIT, permissions.RESOURCE_CONNECTION),
+ (permissions.ACTION_CAN_DELETE, permissions.RESOURCE_CONNECTION),
],
)
create_user(cls.app, username="test_no_permissions", role_name="TestNoPermissions") # type: ignore
diff --git a/tests/api_connexion/endpoints/test_dag_endpoint.py b/tests/api_connexion/endpoints/test_dag_endpoint.py
index 692159e..6238e87 100644
--- a/tests/api_connexion/endpoints/test_dag_endpoint.py
+++ b/tests/api_connexion/endpoints/test_dag_endpoint.py
@@ -53,10 +53,10 @@ class TestDagEndpoint(unittest.TestCase):
username="test",
role_name="Test",
permissions=[
- ("can_create", permissions.RESOURCE_DAGS),
- ("can_read", permissions.RESOURCE_DAGS),
- ("can_edit", permissions.RESOURCE_DAGS),
- ("can_delete", permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_CREATE, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_EDIT, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_DELETE, permissions.RESOURCE_DAGS),
],
)
create_user(cls.app, username="test_no_permissions", role_name="TestNoPermissions") # type: ignore
@@ -64,7 +64,8 @@ class TestDagEndpoint(unittest.TestCase):
cls.app, username="test_granular_permissions", role_name="TestGranularDag" # type: ignore
)
cls.app.appbuilder.sm.sync_perm_for_dag( # type: ignore # pylint: disable=no-member
- "TEST_DAG_1", access_control={'TestGranularDag': ['can_edit', 'can_read']}
+ "TEST_DAG_1",
+ access_control={'TestGranularDag': [permissions.ACTION_CAN_EDIT, permissions.ACTION_CAN_READ]},
)
with DAG(cls.dag_id, start_date=datetime(2020, 6, 15), doc_md="details") as dag:
diff --git a/tests/api_connexion/endpoints/test_dag_run_endpoint.py b/tests/api_connexion/endpoints/test_dag_run_endpoint.py
index 8008bee..f00060b 100644
--- a/tests/api_connexion/endpoints/test_dag_run_endpoint.py
+++ b/tests/api_connexion/endpoints/test_dag_run_endpoint.py
@@ -43,21 +43,22 @@ class TestDagRunEndpoint(unittest.TestCase):
username="test",
role_name="Test",
permissions=[
- ("can_read", permissions.RESOURCE_DAGS),
- ("can_create", "DagRun"),
- ("can_read", "DagRun"),
- ("can_edit", "DagRun"),
- ("can_delete", "DagRun"),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_CREATE, permissions.RESOURCE_DAG_RUN),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ (permissions.ACTION_CAN_EDIT, permissions.RESOURCE_DAG_RUN),
+ (permissions.ACTION_CAN_DELETE, permissions.RESOURCE_DAG_RUN),
],
)
create_user(
cls.app, # type: ignore
username="test_granular_permissions",
role_name="TestGranularDag",
- permissions=[("can_read", "DagRun")],
+ permissions=[(permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN)],
)
cls.app.appbuilder.sm.sync_perm_for_dag( # type: ignore # pylint: disable=no-member
- "TEST_DAG_ID", access_control={'TestGranularDag': ['can_edit', 'can_read']}
+ "TEST_DAG_ID",
+ access_control={'TestGranularDag': [permissions.ACTION_CAN_EDIT, permissions.ACTION_CAN_READ]},
)
create_user(cls.app, username="test_no_permissions", role_name="TestNoPermissions") # type: ignore
diff --git a/tests/api_connexion/endpoints/test_dag_source_endpoint.py b/tests/api_connexion/endpoints/test_dag_source_endpoint.py
index bed03ac..21066c6 100644
--- a/tests/api_connexion/endpoints/test_dag_source_endpoint.py
+++ b/tests/api_connexion/endpoints/test_dag_source_endpoint.py
@@ -25,6 +25,7 @@ from parameterized import parameterized
from airflow import DAG
from airflow.configuration import conf
from airflow.models import DagBag
+from airflow.security import permissions
from airflow.www import app
from tests.test_utils.api_connexion_utils import assert_401, create_user, delete_user
from tests.test_utils.config import conf_vars
@@ -41,7 +42,10 @@ class TestGetSource(unittest.TestCase):
with conf_vars({("api", "auth_backend"): "tests.test_utils.remote_user_api_auth_backend"}):
cls.app = app.create_app(testing=True) # type:ignore
create_user(
- cls.app, username="test", role_name="Test", permissions=[("can_read", "DagCode")] # type: ignore
+ cls.app, # type:ignore
+ username="test",
+ role_name="Test",
+ permissions=[(permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_CODE)], # type: ignore
)
create_user(cls.app, username="test_no_permissions", role_name="TestNoPermissions") # type: ignore
diff --git a/tests/api_connexion/endpoints/test_event_log_endpoint.py b/tests/api_connexion/endpoints/test_event_log_endpoint.py
index 966b17d..ac0ecc5 100644
--- a/tests/api_connexion/endpoints/test_event_log_endpoint.py
+++ b/tests/api_connexion/endpoints/test_event_log_endpoint.py
@@ -22,6 +22,7 @@ from airflow import DAG
from airflow.api_connexion.exceptions import EXCEPTIONS_LINK_MAP
from airflow.models import Log, TaskInstance
from airflow.operators.dummy_operator import DummyOperator
+from airflow.security import permissions
from airflow.utils import timezone
from airflow.utils.session import provide_session
from airflow.www import app
@@ -37,7 +38,10 @@ class TestEventLogEndpoint(unittest.TestCase):
with conf_vars({("api", "auth_backend"): "tests.test_utils.remote_user_api_auth_backend"}):
cls.app = app.create_app(testing=True) # type:ignore
create_user(
- cls.app, username="test", role_name="Test", permissions=[("can_read", "Log")] # type: ignore
+ cls.app, # type:ignore
+ username="test",
+ role_name="Test",
+ permissions=[(permissions.ACTION_CAN_READ, permissions.RESOURCE_LOG)], # type: ignore
)
create_user(cls.app, username="test_no_permissions", role_name="TestNoPermissions") # type: ignore
diff --git a/tests/api_connexion/endpoints/test_extra_link_endpoint.py b/tests/api_connexion/endpoints/test_extra_link_endpoint.py
index 4fef5bf..3cb0506 100644
--- a/tests/api_connexion/endpoints/test_extra_link_endpoint.py
+++ b/tests/api_connexion/endpoints/test_extra_link_endpoint.py
@@ -52,10 +52,10 @@ class TestGetExtraLinks(unittest.TestCase):
username="test",
role_name="Test",
permissions=[
- ('can_read', permissions.RESOURCE_DAGS),
- ('can_read', 'DagRun'),
- ('can_read', 'Task'),
- ('can_read', 'TaskInstance'),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK_INSTANCE),
],
)
create_user(cls.app, username="test_no_permissions", role_name="TestNoPermissions") # type: ignore
diff --git a/tests/api_connexion/endpoints/test_import_error_endpoint.py b/tests/api_connexion/endpoints/test_import_error_endpoint.py
index 63198d4..66eef60 100644
--- a/tests/api_connexion/endpoints/test_import_error_endpoint.py
+++ b/tests/api_connexion/endpoints/test_import_error_endpoint.py
@@ -20,6 +20,7 @@ from parameterized import parameterized
from airflow.api_connexion.exceptions import EXCEPTIONS_LINK_MAP
from airflow.models.errors import ImportError # pylint: disable=redefined-builtin
+from airflow.security import permissions
from airflow.utils import timezone
from airflow.utils.session import provide_session
from airflow.www import app
@@ -38,7 +39,7 @@ class TestBaseImportError(unittest.TestCase):
cls.app, # type: ignore
username="test",
role_name="Test",
- permissions=[('can_read', 'ImportError')],
+ permissions=[(permissions.ACTION_CAN_READ, permissions.RESOURCE_IMPORT_ERROR)],
)
create_user(cls.app, username="test_no_permissions", role_name="TestNoPermissions") # type: ignore
diff --git a/tests/api_connexion/endpoints/test_log_endpoint.py b/tests/api_connexion/endpoints/test_log_endpoint.py
index 5ece059..2a38862 100644
--- a/tests/api_connexion/endpoints/test_log_endpoint.py
+++ b/tests/api_connexion/endpoints/test_log_endpoint.py
@@ -58,9 +58,9 @@ class TestGetLog(unittest.TestCase):
username="test",
role_name="Test",
permissions=[
- ('can_read', permissions.RESOURCE_DAGS),
- ('can_read', 'DagRun'),
- ('can_read', 'Task'),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK),
],
)
create_user(cls.app, username="test_no_permissions", role_name="TestNoPermissions")
diff --git a/tests/api_connexion/endpoints/test_pool_endpoint.py b/tests/api_connexion/endpoints/test_pool_endpoint.py
index 9ccfc77..e099da3 100644
--- a/tests/api_connexion/endpoints/test_pool_endpoint.py
+++ b/tests/api_connexion/endpoints/test_pool_endpoint.py
@@ -20,6 +20,7 @@ from parameterized import parameterized
from airflow.api_connexion.exceptions import EXCEPTIONS_LINK_MAP
from airflow.models.pool import Pool
+from airflow.security import permissions
from airflow.utils.session import provide_session
from airflow.www import app
from tests.test_utils.api_connexion_utils import assert_401, create_user, delete_user
@@ -39,10 +40,10 @@ class TestBasePoolEndpoints(unittest.TestCase):
username="test",
role_name="Test",
permissions=[
- ("can_create", "Pool"),
- ("can_read", "Pool"),
- ("can_edit", "Pool"),
- ("can_delete", "Pool"),
+ (permissions.ACTION_CAN_CREATE, permissions.RESOURCE_POOL),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_POOL),
+ (permissions.ACTION_CAN_EDIT, permissions.RESOURCE_POOL),
+ (permissions.ACTION_CAN_DELETE, permissions.RESOURCE_POOL),
],
)
create_user(cls.app, username="test_no_permissions", role_name="TestNoPermissions") # type: ignore
diff --git a/tests/api_connexion/endpoints/test_task_endpoint.py b/tests/api_connexion/endpoints/test_task_endpoint.py
index 939d587..301ea39 100644
--- a/tests/api_connexion/endpoints/test_task_endpoint.py
+++ b/tests/api_connexion/endpoints/test_task_endpoint.py
@@ -49,9 +49,9 @@ class TestTaskEndpoint(unittest.TestCase):
username="test",
role_name="Test",
permissions=[
- ('can_read', permissions.RESOURCE_DAGS),
- ('can_read', 'DagRun'),
- ('can_read', 'Task'),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK),
],
)
create_user(cls.app, username="test_no_permissions", role_name="TestNoPermissions") # type: ignore
diff --git a/tests/api_connexion/endpoints/test_task_instance_endpoint.py b/tests/api_connexion/endpoints/test_task_instance_endpoint.py
index 9413920..d171bfe 100644
--- a/tests/api_connexion/endpoints/test_task_instance_endpoint.py
+++ b/tests/api_connexion/endpoints/test_task_instance_endpoint.py
@@ -16,6 +16,7 @@
# under the License.
import unittest
import datetime as dt
+import getpass
from unittest import mock
from parameterized import parameterized
@@ -47,10 +48,10 @@ class TestTaskInstanceEndpoint(unittest.TestCase):
username="test",
role_name="Test",
permissions=[
- ('can_read', permissions.RESOURCE_DAGS),
- ('can_read', 'DagRun'),
- ('can_read', 'Task'),
- ('can_edit', 'Task'),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK),
+ (permissions.ACTION_CAN_EDIT, permissions.RESOURCE_TASK),
],
)
create_user(cls.app, username="test_no_permissions", role_name="TestNoPermissions") # type: ignore
@@ -163,7 +164,7 @@ class TestGetTaskInstance(TestTaskInstanceEndpoint):
"state": "running",
"task_id": "print_the_context",
"try_number": 0,
- "unixname": "root",
+ "unixname": getpass.getuser(),
},
)
@@ -215,7 +216,7 @@ class TestGetTaskInstance(TestTaskInstanceEndpoint):
"state": "running",
"task_id": "print_the_context",
"try_number": 0,
- "unixname": "root",
+ "unixname": getpass.getuser(),
},
)
diff --git a/tests/api_connexion/endpoints/test_variable_endpoint.py b/tests/api_connexion/endpoints/test_variable_endpoint.py
index 0c267d3..dc41185 100644
--- a/tests/api_connexion/endpoints/test_variable_endpoint.py
+++ b/tests/api_connexion/endpoints/test_variable_endpoint.py
@@ -18,6 +18,7 @@ import unittest
from parameterized import parameterized
+from airflow.security import permissions
from airflow.api_connexion.exceptions import EXCEPTIONS_LINK_MAP
from airflow.models import Variable
from airflow.www import app
@@ -38,10 +39,10 @@ class TestVariableEndpoint(unittest.TestCase):
username="test",
role_name="Test",
permissions=[
- ("can_create", "Variable"),
- ("can_read", "Variable"),
- ("can_edit", "Variable"),
- ("can_delete", "Variable"),
+ (permissions.ACTION_CAN_CREATE, permissions.RESOURCE_VARIABLE),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_VARIABLE),
+ (permissions.ACTION_CAN_EDIT, permissions.RESOURCE_VARIABLE),
+ (permissions.ACTION_CAN_DELETE, permissions.RESOURCE_VARIABLE),
],
)
create_user(cls.app, username="test_no_permissions", role_name="TestNoPermissions") # type: ignore
diff --git a/tests/api_connexion/endpoints/test_xcom_endpoint.py b/tests/api_connexion/endpoints/test_xcom_endpoint.py
index b8fc5f7..517286f 100644
--- a/tests/api_connexion/endpoints/test_xcom_endpoint.py
+++ b/tests/api_connexion/endpoints/test_xcom_endpoint.py
@@ -41,20 +41,25 @@ class TestXComEndpoint(unittest.TestCase):
username="test",
role_name="Test",
permissions=[
- ("can_read", permissions.RESOURCE_DAGS),
- ("can_read", "DagRun"),
- ("can_read", "Task"),
- ("can_read", "XCom"),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_XCOM),
],
)
create_user(
cls.app, # type: ignore
username="test_granular_permissions",
role_name="TestGranularDag",
- permissions=[("can_read", "DagRun"), ("can_read", "Task"), ("can_read", "XCom")],
+ permissions=[
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_RUN),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK),
+ (permissions.ACTION_CAN_READ, permissions.RESOURCE_XCOM),
+ ],
)
cls.app.appbuilder.sm.sync_perm_for_dag( # type: ignore # pylint: disable=no-member
- "test-dag-id-1", access_control={'TestGranularDag': ['can_edit', 'can_read']}
+ "test-dag-id-1",
+ access_control={'TestGranularDag': [permissions.ACTION_CAN_EDIT, permissions.ACTION_CAN_READ]},
)
create_user(cls.app, username="test_no_permissions", role_name="TestNoPermissions") # type: ignore
diff --git a/tests/api_connexion/schemas/test_task_instance_schema.py b/tests/api_connexion/schemas/test_task_instance_schema.py
index f806442..c164aec 100644
--- a/tests/api_connexion/schemas/test_task_instance_schema.py
+++ b/tests/api_connexion/schemas/test_task_instance_schema.py
@@ -16,6 +16,7 @@
# under the License.
import datetime as dt
+import getpass
import unittest
from marshmallow import ValidationError
@@ -85,7 +86,7 @@ class TestTaskInstanceSchema(unittest.TestCase):
"state": "running",
"task_id": "TEST_TASK_ID",
"try_number": 0,
- "unixname": "root",
+ "unixname": getpass.getuser(),
}
self.assertDictEqual(serialized_ti, expected_json)
@@ -131,7 +132,7 @@ class TestTaskInstanceSchema(unittest.TestCase):
"state": "running",
"task_id": "TEST_TASK_ID",
"try_number": 0,
- "unixname": "root",
+ "unixname": getpass.getuser(),
}
self.assertDictEqual(serialized_ti, expected_json)
diff --git a/tests/cli/commands/test_sync_perm_command.py b/tests/cli/commands/test_sync_perm_command.py
index 8d2f117..d3422b6 100644
--- a/tests/cli/commands/test_sync_perm_command.py
+++ b/tests/cli/commands/test_sync_perm_command.py
@@ -23,6 +23,7 @@ from airflow.cli import cli_parser
from airflow.cli.commands import sync_perm_command
from airflow.models.dag import DAG
from airflow.models.dagbag import DagBag
+from airflow.security import permissions
class TestCliSyncPerm(unittest.TestCase):
@@ -38,7 +39,7 @@ class TestCliSyncPerm(unittest.TestCase):
self.expect_dagbag_contains([
DAG('has_access_control',
access_control={
- 'Public': {'can_read'}
+ 'Public': {permissions.ACTION_CAN_READ}
}),
DAG('no_access_control')
], dagbag_mock)
@@ -56,7 +57,7 @@ class TestCliSyncPerm(unittest.TestCase):
self.assertEqual(2, len(appbuilder.sm.sync_perm_for_dag.mock_calls))
appbuilder.sm.sync_perm_for_dag.assert_any_call(
'has_access_control',
- {'Public': {'can_read'}}
+ {'Public': {permissions.ACTION_CAN_READ}}
)
appbuilder.sm.sync_perm_for_dag.assert_any_call(
'no_access_control',
diff --git a/tests/models/test_dag.py b/tests/models/test_dag.py
index afe42e3..16ee3e0 100644
--- a/tests/models/test_dag.py
+++ b/tests/models/test_dag.py
@@ -44,6 +44,7 @@ from airflow.models.baseoperator import BaseOperator
from airflow.operators.bash import BashOperator
from airflow.operators.dummy_operator import DummyOperator
from airflow.operators.subdag_operator import SubDagOperator
+from airflow.security import permissions
from airflow.utils import timezone
from airflow.utils.file import list_py_file_paths
from airflow.utils.session import create_session, provide_session
@@ -1663,8 +1664,14 @@ class TestDag(unittest.TestCase):
assert next_subdag_date is None, "SubDags should never have DagRuns created by the scheduler"
def test_replace_outdated_access_control_actions(self):
- outdated_permissions = {'role1': {'can_read', 'can_edit'}, 'role2': {'can_dag_read', 'can_dag_edit'}}
- updated_permissions = {'role1': {'can_read', 'can_edit'}, 'role2': {'can_read', 'can_edit'}}
+ outdated_permissions = {
+ 'role1': {permissions.ACTION_CAN_READ, permissions.ACTION_CAN_EDIT},
+ 'role2': {permissions.DEPRECATED_ACTION_CAN_DAG_READ, permissions.DEPRECATED_ACTION_CAN_DAG_EDIT}
+ }
+ updated_permissions = {
+ 'role1': {permissions.ACTION_CAN_READ, permissions.ACTION_CAN_EDIT},
+ 'role2': {permissions.ACTION_CAN_READ, permissions.ACTION_CAN_EDIT}
+ }
with pytest.warns(DeprecationWarning):
dag = DAG(dag_id='dag_with_outdated_perms', access_control=outdated_permissions)
diff --git a/tests/serialization/test_dag_serialization.py b/tests/serialization/test_dag_serialization.py
index a31b44a..39dd3ba 100644
--- a/tests/serialization/test_dag_serialization.py
+++ b/tests/serialization/test_dag_serialization.py
@@ -37,6 +37,7 @@ from airflow.kubernetes.pod_generator import PodGenerator
from airflow.models import DAG, Connection, DagBag, TaskInstance
from airflow.models.baseoperator import BaseOperator
from airflow.operators.bash import BashOperator
+from airflow.security import permissions
from airflow.serialization.json_schema import load_dag_schema_dict
from airflow.serialization.serialized_objects import SerializedBaseOperator, SerializedDAG
from tests.test_utils.mock_operators import CustomOperator, CustomOpLink, GoogleLink
@@ -134,8 +135,8 @@ serialized_simple_dag_ground_truth = {
"test_role": {
"__type": "set",
"__var": [
- "can_read",
- "can_edit"
+ permissions.ACTION_CAN_READ,
+ permissions.ACTION_CAN_EDIT
]
}
}
@@ -166,7 +167,7 @@ def make_simple_dag():
start_date=datetime(2019, 8, 1),
is_paused_upon_creation=False,
access_control={
- "test_role": {"can_read", "can_edit"}
+ "test_role": {permissions.ACTION_CAN_READ, permissions.ACTION_CAN_EDIT}
}
) as dag:
CustomOperator(task_id='custom_task')
diff --git a/tests/www/test_security.py b/tests/www/test_security.py
index f3529b6..9d82697 100644
--- a/tests/www/test_security.py
+++ b/tests/www/test_security.py
@@ -35,8 +35,8 @@ from tests.test_utils import fab_utils
from tests.test_utils.db import clear_db_dags, clear_db_runs
from tests.test_utils.mock_security_manager import MockSecurityManager
-READ_WRITE = {'can_read', 'can_edit'}
-READ_ONLY = {'can_read'}
+READ_WRITE = {permissions.ACTION_CAN_READ, permissions.ACTION_CAN_EDIT}
+READ_ONLY = {permissions.ACTION_CAN_READ}
logging.basicConfig(format='%(asctime)s:%(levelname)s:%(name)s:%(message)s')
logging.getLogger().setLevel(logging.DEBUG)
@@ -56,7 +56,13 @@ class SomeModel(Model):
class SomeModelView(ModelView):
datamodel = CustomSQLAInterface(SomeModel)
- base_permissions = ['can_list', 'can_show', 'can_add', 'can_edit', 'can_delete']
+ base_permissions = [
+ 'can_list',
+ 'can_show',
+ 'can_add',
+ permissions.ACTION_CAN_EDIT,
+ permissions.ACTION_CAN_DELETE,
+ ]
list_columns = ['field_string', 'field_integer', 'field_float', 'field_date']
@@ -141,7 +147,13 @@ class TestSecurity(unittest.TestCase):
def test_init_role_modelview(self):
role_name = 'MyRole2'
- role_perms = ['can_list', 'can_show', 'can_add', 'can_edit', 'can_delete']
+ role_perms = [
+ 'can_list',
+ 'can_show',
+ 'can_add',
+ permissions.ACTION_CAN_EDIT,
+ permissions.ACTION_CAN_DELETE,
+ ]
role_vms = ['SomeModelView']
self.security_manager.init_role(role_name, role_vms, role_perms)
role = self.appbuilder.sm.find_role(role_name)
@@ -153,7 +165,7 @@ class TestSecurity(unittest.TestCase):
self.security_manager.init_role(role_name, [], [])
role = self.security_manager.find_role(role_name)
- perm = self.security_manager.find_permission_view_menu('can_edit', 'RoleModelView')
+ perm = self.security_manager.find_permission_view_menu(permissions.ACTION_CAN_EDIT, 'RoleModelView')
self.security_manager.add_permission_role(role, perm)
role_perms_len = len(role.permissions)
@@ -188,7 +200,7 @@ class TestSecurity(unittest.TestCase):
def test_get_accessible_dag_ids(self):
role_name = 'MyRole1'
- permission_action = ['can_read']
+ permission_action = [permissions.ACTION_CAN_READ]
dag_id = 'dag_id'
username = "ElUser"
@@ -224,10 +236,10 @@ class TestSecurity(unittest.TestCase):
prefixed_test_dag_id = f'DAG:{test_dag_id}'
self.security_manager.sync_perm_for_dag(test_dag_id, access_control=None)
self.assertIsNotNone(
- self.security_manager.find_permission_view_menu('can_read', prefixed_test_dag_id)
+ self.security_manager.find_permission_view_menu(permissions.ACTION_CAN_READ, prefixed_test_dag_id)
)
self.assertIsNotNone(
- self.security_manager.find_permission_view_menu('can_edit', prefixed_test_dag_id)
+ self.security_manager.find_permission_view_menu(permissions.ACTION_CAN_EDIT, prefixed_test_dag_id)
)
@mock.patch('airflow.www.security.AirflowSecurityManager._has_perm')
@@ -247,7 +259,9 @@ class TestSecurity(unittest.TestCase):
with self.assertRaises(AirflowException) as context:
self.security_manager.sync_perm_for_dag(
dag_id='access-control-test',
- access_control={'this-role-does-not-exist': ['can_edit', 'can_read']},
+ access_control={
+ 'this-role-does-not-exist': [permissions.ACTION_CAN_EDIT, permissions.ACTION_CAN_READ]
+ },
)
self.assertIn("role does not exist", str(context.exception))
@@ -267,7 +281,9 @@ class TestSecurity(unittest.TestCase):
self.assertTrue(
self.security_manager.has_access(permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS, user)
)
- self.assertFalse(self.security_manager.has_access(permissions.ACTION_CAN_READ, 'Task', user))
+ self.assertFalse(
+ self.security_manager.has_access(permissions.ACTION_CAN_READ, permissions.RESOURCE_TASK, user)
+ )
def test_access_control_with_invalid_permission(self):
invalid_permissions = [
@@ -291,15 +307,20 @@ class TestSecurity(unittest.TestCase):
user = fab_utils.create_user(self.app, username, role_name, permissions=[],)
self.expect_user_is_in_role(user, rolename='team-a')
self.security_manager.sync_perm_for_dag(
- 'access_control_test', access_control={'team-a': ['can_edit', 'can_read']}
+ 'access_control_test',
+ access_control={'team-a': [permissions.ACTION_CAN_EDIT, permissions.ACTION_CAN_READ]},
)
self.assert_user_has_dag_perms(
- perms=['can_edit', 'can_read'], dag_id='access_control_test', user=user
+ perms=[permissions.ACTION_CAN_EDIT, permissions.ACTION_CAN_READ],
+ dag_id='access_control_test',
+ user=user,
)
self.expect_user_is_in_role(user, rolename='NOT-team-a')
self.assert_user_does_not_have_dag_perms(
- perms=['can_edit', 'can_read'], dag_id='access_control_test', user=user
+ perms=[permissions.ACTION_CAN_EDIT, permissions.ACTION_CAN_READ],
+ dag_id='access_control_test',
+ user=user,
)
def test_access_control_stale_perms_are_revoked(self):
@@ -316,9 +337,11 @@ class TestSecurity(unittest.TestCase):
self.security_manager.sync_perm_for_dag(
'access_control_test', access_control={'team-a': READ_ONLY}
)
- self.assert_user_has_dag_perms(perms=['can_read'], dag_id='access_control_test', user=user)
+ self.assert_user_has_dag_perms(
+ perms=[permissions.ACTION_CAN_READ], dag_id='access_control_test', user=user
+ )
self.assert_user_does_not_have_dag_perms(
- perms=['can_edit'], dag_id='access_control_test', user=user
+ perms=[permissions.ACTION_CAN_EDIT], dag_id='access_control_test', user=user
)
def test_no_additional_dag_permission_views_created(self):
diff --git a/tests/www/test_views.py b/tests/www/test_views.py
index e66b3d8..cf9fef2 100644
--- a/tests/www/test_views.py
+++ b/tests/www/test_views.py
@@ -1735,18 +1735,18 @@ class TestDagACLView(TestBase):
password='test')
dag_tester_role = self.appbuilder.sm.find_role('dag_acl_tester')
edit_perm_on_dag = self.appbuilder.sm.\
- find_permission_view_menu('can_edit', 'DAG:example_bash_operator')
+ find_permission_view_menu(permissions.ACTION_CAN_EDIT, 'DAG:example_bash_operator')
self.appbuilder.sm.add_permission_role(dag_tester_role, edit_perm_on_dag)
read_perm_on_dag = self.appbuilder.sm.\
- find_permission_view_menu('can_read', 'DAG:example_bash_operator')
+ find_permission_view_menu(permissions.ACTION_CAN_READ, 'DAG:example_bash_operator')
self.appbuilder.sm.add_permission_role(dag_tester_role, read_perm_on_dag)
all_dag_role = self.appbuilder.sm.find_role('all_dag_role')
edit_perm_on_all_dag = self.appbuilder.sm.\
- find_permission_view_menu('can_edit', permissions.RESOURCE_DAGS)
+ find_permission_view_menu(permissions.ACTION_CAN_EDIT, permissions.RESOURCE_DAGS)
self.appbuilder.sm.add_permission_role(all_dag_role, edit_perm_on_all_dag)
read_perm_on_all_dag = self.appbuilder.sm.\
- find_permission_view_menu('can_read', permissions.RESOURCE_DAGS)
+ find_permission_view_menu(permissions.ACTION_CAN_READ, permissions.RESOURCE_DAGS)
self.appbuilder.sm.add_permission_role(all_dag_role, read_perm_on_all_dag)
role_user = self.appbuilder.sm.find_role('User')
@@ -1754,7 +1754,7 @@ class TestDagACLView(TestBase):
self.appbuilder.sm.add_permission_role(role_user, edit_perm_on_all_dag)
read_only_perm_on_dag = self.appbuilder.sm.\
- find_permission_view_menu('can_read', 'DAG:example_bash_operator')
+ find_permission_view_menu(permissions.ACTION_CAN_READ, 'DAG:example_bash_operator')
dag_read_only_role = self.appbuilder.sm.find_role('dag_acl_read_only')
self.appbuilder.sm.add_permission_role(dag_read_only_role, read_only_perm_on_dag)