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 8741e9c176 Handle `AUTH_ROLE_PUBLIC` in FAB auth manager (#42280)
8741e9c176 is described below
commit 8741e9c1761931c7cff135d53b589053a04f58c1
Author: Vincent <[email protected]>
AuthorDate: Fri Sep 20 13:52:43 2024 -0700
Handle `AUTH_ROLE_PUBLIC` in FAB auth manager (#42280)
---
.../endpoints/forward_to_fab_endpoint.py | 131 ------
airflow/api_connexion/openapi/v1.yaml | 310 ---------------
airflow/api_connexion/security.py | 5 -
.../config_templates/default_webserver_config.py | 2 +-
.../auth_manager/api/auth/backend/basic_auth.py | 6 +-
.../auth_manager/api/auth/backend/kerberos_auth.py | 6 +-
.../providers/fab/auth_manager/fab_auth_manager.py | 17 +-
.../fab/auth_manager/models/anonymous_user.py | 8 +-
.../fab/auth_manager/security_manager/override.py | 6 +-
airflow/www/static/js/types/api-generated.ts | 441 ---------------------
airflow/www/utils.py | 11 +-
airflow/www/views.py | 4 +-
newsfragments/42280.significant.rst | 5 +
tests/api_connexion/conftest.py | 11 -
.../endpoints/test_config_endpoint.py | 22 -
.../endpoints/test_connection_endpoint.py | 89 -----
tests/api_connexion/endpoints/test_dag_endpoint.py | 99 -----
.../endpoints/test_dag_run_endpoint.py | 185 ---------
.../endpoints/test_dag_source_endpoint.py | 16 -
.../endpoints/test_dag_warning_endpoint.py | 12 -
.../endpoints/test_dataset_endpoint.py | 184 ---------
.../endpoints/test_event_log_endpoint.py | 44 --
.../endpoints/test_forward_to_fab_endpoint.py | 238 -----------
.../test_role_and_permission_endpoint.py | 12 +-
.../api_endpoints/test_user_endpoint.py | 1 +
tests/providers/fab/auth_manager/conftest.py | 9 +-
.../fab/auth_manager/test_fab_auth_manager.py | 10 +-
27 files changed, 60 insertions(+), 1824 deletions(-)
diff --git a/airflow/api_connexion/endpoints/forward_to_fab_endpoint.py
b/airflow/api_connexion/endpoints/forward_to_fab_endpoint.py
deleted file mode 100644
index 9785a5b053..0000000000
--- a/airflow/api_connexion/endpoints/forward_to_fab_endpoint.py
+++ /dev/null
@@ -1,131 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-from __future__ import annotations
-
-import warnings
-from typing import TYPE_CHECKING
-
-from airflow.api_connexion.exceptions import BadRequest
-from airflow.providers.fab.auth_manager.api_endpoints import
role_and_permission_endpoint, user_endpoint
-from airflow.www.extensions.init_auth_manager import get_auth_manager
-
-if TYPE_CHECKING:
- from typing import Callable
-
- from airflow.api_connexion.types import APIResponse
-
-
-def _require_fab(func: Callable) -> Callable:
- """
- Raise an HTTP error 400 if the auth manager is not FAB.
-
- Intended to decorate endpoints that have been migrated from Airflow API to
FAB API.
- """
-
- def inner(*args, **kwargs):
- from airflow.providers.fab.auth_manager.fab_auth_manager import
FabAuthManager
-
- auth_mgr = get_auth_manager()
- if not isinstance(auth_mgr, FabAuthManager):
- raise BadRequest(
- detail="This endpoint is only available when using the default
auth manager FabAuthManager."
- )
- else:
- warnings.warn(
- "This API endpoint is deprecated. "
- "Please use the API under /auth/fab/v1 instead for this
operation.",
- DeprecationWarning,
- stacklevel=1, # This decorator wrapped multiple times, better
point to this file
- )
- return func(*args, **kwargs)
-
- return inner
-
-
-### role
-
-
-@_require_fab
-def get_role(**kwargs) -> APIResponse:
- """Get role."""
- return role_and_permission_endpoint.get_role(**kwargs)
-
-
-@_require_fab
-def get_roles(**kwargs) -> APIResponse:
- """Get roles."""
- return role_and_permission_endpoint.get_roles(**kwargs)
-
-
-@_require_fab
-def delete_role(**kwargs) -> APIResponse:
- """Delete a role."""
- return role_and_permission_endpoint.delete_role(**kwargs)
-
-
-@_require_fab
-def patch_role(**kwargs) -> APIResponse:
- """Update a role."""
- kwargs.pop("body", None)
- return role_and_permission_endpoint.patch_role(**kwargs)
-
-
-@_require_fab
-def post_role(**kwargs) -> APIResponse:
- """Create a new role."""
- kwargs.pop("body", None)
- return role_and_permission_endpoint.post_role(**kwargs)
-
-
-### permissions
-@_require_fab
-def get_permissions(**kwargs) -> APIResponse:
- """Get permissions."""
- return role_and_permission_endpoint.get_permissions(**kwargs)
-
-
-### user
-@_require_fab
-def get_user(**kwargs) -> APIResponse:
- """Get a user."""
- return user_endpoint.get_user(**kwargs)
-
-
-@_require_fab
-def get_users(**kwargs) -> APIResponse:
- """Get users."""
- return user_endpoint.get_users(**kwargs)
-
-
-@_require_fab
-def post_user(**kwargs) -> APIResponse:
- """Create a new user."""
- kwargs.pop("body", None)
- return user_endpoint.post_user(**kwargs)
-
-
-@_require_fab
-def patch_user(**kwargs) -> APIResponse:
- """Update a user."""
- kwargs.pop("body", None)
- return user_endpoint.patch_user(**kwargs)
-
-
-@_require_fab
-def delete_user(**kwargs) -> APIResponse:
- """Delete a user."""
- return user_endpoint.delete_user(**kwargs)
diff --git a/airflow/api_connexion/openapi/v1.yaml
b/airflow/api_connexion/openapi/v1.yaml
index 24b9c1be0d..07cb7fcb74 100644
--- a/airflow/api_connexion/openapi/v1.yaml
+++ b/airflow/api_connexion/openapi/v1.yaml
@@ -2591,316 +2591,6 @@ paths:
"404":
$ref: "#/components/responses/NotFound"
- /roles:
- get:
- deprecated: true
- summary: List roles
- description: |
- Get a list of roles.
-
- *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- x-openapi-router-controller:
airflow.api_connexion.endpoints.forward_to_fab_endpoint
- operationId: get_roles
- tags: [Role]
- parameters:
- - $ref: "#/components/parameters/PageLimit"
- - $ref: "#/components/parameters/PageOffset"
- - $ref: "#/components/parameters/OrderBy"
- responses:
- "200":
- description: Success.
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/RoleCollection"
- "401":
- $ref: "#/components/responses/Unauthenticated"
- "403":
- $ref: "#/components/responses/PermissionDenied"
-
- post:
- deprecated: true
- summary: Create a role
- description: |
- Create a new role.
-
- *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- x-openapi-router-controller:
airflow.api_connexion.endpoints.forward_to_fab_endpoint
- operationId: post_role
- tags: [Role]
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/Role"
- responses:
- "200":
- description: Success.
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/Role"
- "400":
- $ref: "#/components/responses/BadRequest"
- "401":
- $ref: "#/components/responses/Unauthenticated"
- "403":
- $ref: "#/components/responses/PermissionDenied"
-
- /roles/{role_name}:
- parameters:
- - $ref: "#/components/parameters/RoleName"
-
- get:
- deprecated: true
- summary: Get a role
- description: |
- Get a role.
-
- *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- x-openapi-router-controller:
airflow.api_connexion.endpoints.forward_to_fab_endpoint
- operationId: get_role
- tags: [Role]
- responses:
- "200":
- description: Success.
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/Role"
- "401":
- $ref: "#/components/responses/Unauthenticated"
- "403":
- $ref: "#/components/responses/PermissionDenied"
- "404":
- $ref: "#/components/responses/NotFound"
-
- patch:
- deprecated: true
- summary: Update a role
- description: |
- Update a role.
-
- *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- x-openapi-router-controller:
airflow.api_connexion.endpoints.forward_to_fab_endpoint
- operationId: patch_role
- tags: [Role]
- parameters:
- - $ref: "#/components/parameters/UpdateMask"
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/Role"
-
- responses:
- "200":
- description: Success.
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/Role"
- "400":
- $ref: "#/components/responses/BadRequest"
- "401":
- $ref: "#/components/responses/Unauthenticated"
- "403":
- $ref: "#/components/responses/PermissionDenied"
- "404":
- $ref: "#/components/responses/NotFound"
-
- delete:
- deprecated: true
- summary: Delete a role
- description: |
- Delete a role.
-
- *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- x-openapi-router-controller:
airflow.api_connexion.endpoints.forward_to_fab_endpoint
- operationId: delete_role
- tags: [Role]
- responses:
- "204":
- description: Success.
- "400":
- $ref: "#/components/responses/BadRequest"
- "401":
- $ref: "#/components/responses/Unauthenticated"
- "403":
- $ref: "#/components/responses/PermissionDenied"
- "404":
- $ref: "#/components/responses/NotFound"
-
- /permissions:
- get:
- deprecated: true
- summary: List permissions
- description: |
- Get a list of permissions.
-
- *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- x-openapi-router-controller:
airflow.api_connexion.endpoints.forward_to_fab_endpoint
- operationId: get_permissions
- tags: [Permission]
- parameters:
- - $ref: "#/components/parameters/PageLimit"
- - $ref: "#/components/parameters/PageOffset"
- responses:
- "200":
- description: Success.
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ActionCollection"
- "401":
- $ref: "#/components/responses/Unauthenticated"
- "403":
- $ref: "#/components/responses/PermissionDenied"
-
- /users:
- get:
- deprecated: true
- summary: List users
- description: |
- Get a list of users.
-
- *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- x-openapi-router-controller:
airflow.api_connexion.endpoints.forward_to_fab_endpoint
- operationId: get_users
- tags: [User]
- parameters:
- - $ref: "#/components/parameters/PageLimit"
- - $ref: "#/components/parameters/PageOffset"
- - $ref: "#/components/parameters/OrderBy"
- responses:
- "200":
- description: Success.
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/UserCollection"
- "401":
- $ref: "#/components/responses/Unauthenticated"
- "403":
- $ref: "#/components/responses/PermissionDenied"
-
- post:
- deprecated: true
- summary: Create a user
- description: |
- Create a new user with unique username and email.
-
- *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- x-openapi-router-controller:
airflow.api_connexion.endpoints.forward_to_fab_endpoint
- operationId: post_user
- tags: [User]
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/User"
- responses:
- "200":
- description: Success.
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/User"
- "400":
- $ref: "#/components/responses/BadRequest"
- "401":
- $ref: "#/components/responses/Unauthenticated"
- "403":
- $ref: "#/components/responses/PermissionDenied"
- "409":
- $ref: "#/components/responses/AlreadyExists"
-
- /users/{username}:
- parameters:
- - $ref: "#/components/parameters/Username"
- get:
- deprecated: true
- summary: Get a user
- description: |
- Get a user with a specific username.
-
- *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- x-openapi-router-controller:
airflow.api_connexion.endpoints.forward_to_fab_endpoint
- operationId: get_user
- tags: [User]
- responses:
- "200":
- description: Success.
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/UserCollectionItem"
- "401":
- $ref: "#/components/responses/Unauthenticated"
- "403":
- $ref: "#/components/responses/PermissionDenied"
- "404":
- $ref: "#/components/responses/NotFound"
-
- patch:
- deprecated: true
- summary: Update a user
- description: |
- Update fields for a user.
-
- *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- x-openapi-router-controller:
airflow.api_connexion.endpoints.forward_to_fab_endpoint
- operationId: patch_user
- tags: [User]
- parameters:
- - $ref: "#/components/parameters/UpdateMask"
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/User"
- responses:
- "200":
- description: Success.
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/UserCollectionItem"
- "400":
- $ref: "#/components/responses/BadRequest"
- "401":
- $ref: "#/components/responses/Unauthenticated"
- "403":
- $ref: "#/components/responses/PermissionDenied"
- "404":
- $ref: "#/components/responses/NotFound"
-
- delete:
- deprecated: true
- summary: Delete a user
- description: |
- Delete a user with a specific username.
-
- *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- x-openapi-router-controller:
airflow.api_connexion.endpoints.forward_to_fab_endpoint
- operationId: delete_user
- tags: [User]
- responses:
- "204":
- description: Success.
- "400":
- $ref: "#/components/responses/BadRequest"
- "401":
- $ref: "#/components/responses/Unauthenticated"
- "403":
- $ref: "#/components/responses/PermissionDenied"
- "404":
- $ref: "#/components/responses/NotFound"
-
components:
# Reusable schemas (data models)
schemas:
diff --git a/airflow/api_connexion/security.py
b/airflow/api_connexion/security.py
index c6474fd600..7b0a026e09 100644
--- a/airflow/api_connexion/security.py
+++ b/airflow/api_connexion/security.py
@@ -48,11 +48,6 @@ def check_authentication() -> None:
if response.status_code == 200:
return
- # Even if the current_user is anonymous, the AUTH_ROLE_PUBLIC might still
have permission.
- appbuilder = get_airflow_app().appbuilder
- if appbuilder.get_app.config.get("AUTH_ROLE_PUBLIC", None):
- return
-
# since this handler only checks authentication, not authorization,
# we should always return 401
raise Unauthenticated(headers=response.headers)
diff --git a/airflow/config_templates/default_webserver_config.py
b/airflow/config_templates/default_webserver_config.py
index 71bdf9e99d..5ef855ae4a 100644
--- a/airflow/config_templates/default_webserver_config.py
+++ b/airflow/config_templates/default_webserver_config.py
@@ -36,7 +36,7 @@ WTF_CSRF_ENABLED = True
WTF_CSRF_TIME_LIMIT = None
# ----------------------------------------------------
-# AUTHENTICATION CONFIG
+# AUTHENTICATION CONFIG (specific to FAB auth manager)
# ----------------------------------------------------
# For details on how to set up each of the following authentication, see
# http://flask-appbuilder.readthedocs.io/en/latest/security.html#
authentication-methods
diff --git a/airflow/providers/fab/auth_manager/api/auth/backend/basic_auth.py
b/airflow/providers/fab/auth_manager/api/auth/backend/basic_auth.py
index ff7c2cc3b3..3a0328fe99 100644
--- a/airflow/providers/fab/auth_manager/api/auth/backend/basic_auth.py
+++ b/airflow/providers/fab/auth_manager/api/auth/backend/basic_auth.py
@@ -21,7 +21,7 @@ from __future__ import annotations
from functools import wraps
from typing import TYPE_CHECKING, Any, Callable, TypeVar, cast
-from flask import Response, request
+from flask import Response, current_app, request
from flask_appbuilder.const import AUTH_LDAP
from flask_login import login_user
@@ -62,7 +62,9 @@ def requires_authentication(function: T):
@wraps(function)
def decorated(*args, **kwargs):
- if auth_current_user() is not None:
+ if auth_current_user() is not None or
current_app.appbuilder.get_app.config.get(
+ "AUTH_ROLE_PUBLIC", None
+ ):
return function(*args, **kwargs)
else:
return Response("Unauthorized", 401, {"WWW-Authenticate": "Basic"})
diff --git
a/airflow/providers/fab/auth_manager/api/auth/backend/kerberos_auth.py
b/airflow/providers/fab/auth_manager/api/auth/backend/kerberos_auth.py
index b2c4585301..d8d5a95ee6 100644
--- a/airflow/providers/fab/auth_manager/api/auth/backend/kerberos_auth.py
+++ b/airflow/providers/fab/auth_manager/api/auth/backend/kerberos_auth.py
@@ -23,7 +23,7 @@ from functools import wraps
from typing import TYPE_CHECKING, Any, Callable, NamedTuple, TypeVar, cast
import kerberos
-from flask import Response, g, make_response, request
+from flask import Response, current_app, g, make_response, request
from requests_kerberos import HTTPKerberosAuth
from airflow.configuration import conf
@@ -124,6 +124,10 @@ def requires_authentication(function: T, find_user:
Callable[[str], BaseUser] |
@wraps(function)
def decorated(*args, **kwargs):
+ if current_app.appbuilder.get_app.config.get("AUTH_ROLE_PUBLIC", None):
+ response = function(*args, **kwargs)
+ return make_response(response)
+
header = request.headers.get("Authorization")
if header:
token = "".join(header.split()[1:])
diff --git a/airflow/providers/fab/auth_manager/fab_auth_manager.py
b/airflow/providers/fab/auth_manager/fab_auth_manager.py
index 336437061c..2de8db2f56 100644
--- a/airflow/providers/fab/auth_manager/fab_auth_manager.py
+++ b/airflow/providers/fab/auth_manager/fab_auth_manager.py
@@ -25,6 +25,7 @@ from typing import TYPE_CHECKING, Container
import packaging.version
from connexion import FlaskApi
from flask import Blueprint, url_for
+from packaging.version import Version
from sqlalchemy import select
from sqlalchemy.orm import Session, joinedload
@@ -84,6 +85,7 @@ from airflow.security.permissions import (
)
from airflow.utils.session import NEW_SESSION, provide_session
from airflow.utils.yaml import safe_load
+from airflow.version import version
from airflow.www.constants import SWAGGER_BUNDLE, SWAGGER_ENABLED
from airflow.www.extensions.init_views import
_CustomErrorRequestBodyValidator, _LazyResolver
@@ -189,7 +191,12 @@ class FabAuthManager(BaseAuthManager):
def is_logged_in(self) -> bool:
"""Return whether the user is logged in."""
user = self.get_user()
- return not user.is_anonymous and user.is_active
+ if Version(Version(version).base_version) < Version("3.0.0"):
+ return not user.is_anonymous and user.is_active
+ else:
+ return self.appbuilder.get_app.config.get("AUTH_ROLE_PUBLIC",
None) or (
+ not user.is_anonymous and user.is_active
+ )
def is_authorized_configuration(
self,
@@ -374,7 +381,9 @@ class FabAuthManager(BaseAuthManager):
def get_url_user_profile(self) -> str | None:
"""Return the url to a page displaying info about the current user."""
- if not self.security_manager.user_view:
+ if not self.security_manager.user_view or
self.appbuilder.get_app.config.get(
+ "AUTH_ROLE_PUBLIC", None
+ ):
return None
return url_for(f"{self.security_manager.user_view.endpoint}.userinfo")
@@ -532,10 +541,6 @@ class FabAuthManager(BaseAuthManager):
# Otherwise, when the name of a view or menu is changed, the framework
# will add the new Views and Menus names to the backend, but will not
# delete the old ones.
- from packaging.version import Version
-
- from airflow.version import version
-
if Version(Version(version).base_version) >= Version("3.0.0"):
fallback = None
else:
diff --git a/airflow/providers/fab/auth_manager/models/anonymous_user.py
b/airflow/providers/fab/auth_manager/models/anonymous_user.py
index ba75de0d3c..2f294fd9e5 100644
--- a/airflow/providers/fab/auth_manager/models/anonymous_user.py
+++ b/airflow/providers/fab/auth_manager/models/anonymous_user.py
@@ -29,10 +29,13 @@ class AnonymousUser(AnonymousUserMixin, BaseUser):
_roles: set[tuple[str, str]] = set()
_perms: set[tuple[str, str]] = set()
+ first_name = "Anonymous"
+ last_name = ""
+
@property
def roles(self):
if not self._roles:
- public_role =
current_app.appbuilder.get_app.config["AUTH_ROLE_PUBLIC"]
+ public_role =
current_app.appbuilder.get_app.config.get("AUTH_ROLE_PUBLIC", None)
self._roles = {current_app.appbuilder.sm.find_role(public_role)}
if public_role else set()
return self._roles
@@ -48,3 +51,6 @@ class AnonymousUser(AnonymousUserMixin, BaseUser):
(perm.action.name, perm.resource.name) for role in self.roles
for perm in role.permissions
}
return self._perms
+
+ def get_name(self) -> str:
+ return "Anonymous"
diff --git a/airflow/providers/fab/auth_manager/security_manager/override.py
b/airflow/providers/fab/auth_manager/security_manager/override.py
index fad32c9f55..0f4b79b4f1 100644
--- a/airflow/providers/fab/auth_manager/security_manager/override.py
+++ b/airflow/providers/fab/auth_manager/security_manager/override.py
@@ -609,7 +609,7 @@ class
FabAirflowSecurityManagerOverride(AirflowSecurityManagerV2):
@property
def auth_role_public(self):
"""Get the public role."""
- return self.appbuilder.get_app.config["AUTH_ROLE_PUBLIC"]
+ return self.appbuilder.get_app.config.get("AUTH_ROLE_PUBLIC", None)
@property
def oauth_providers(self):
@@ -832,7 +832,6 @@ class
FabAirflowSecurityManagerOverride(AirflowSecurityManagerV2):
app = self.appbuilder.get_app
# Base Security Config
app.config.setdefault("AUTH_ROLE_ADMIN", "Admin")
- app.config.setdefault("AUTH_ROLE_PUBLIC", "Public")
app.config.setdefault("AUTH_TYPE", AUTH_DB)
# Self Registration
app.config.setdefault("AUTH_USER_REGISTRATION", False)
@@ -955,7 +954,8 @@ class
FabAirflowSecurityManagerOverride(AirflowSecurityManagerV2):
self.add_role(role_name)
if self.auth_role_admin not in self._builtin_roles:
self.add_role(self.auth_role_admin)
- self.add_role(self.auth_role_public)
+ if self.auth_role_public:
+ self.add_role(self.auth_role_public)
if self.count_users() == 0 and self.auth_role_public !=
self.auth_role_admin:
log.warning(const.LOGMSG_WAR_SEC_NO_USER)
except Exception:
diff --git a/airflow/www/static/js/types/api-generated.ts
b/airflow/www/static/js/types/api-generated.ts
index 8d912574d2..09def0ac66 100644
--- a/airflow/www/static/js/types/api-generated.ts
+++ b/airflow/www/static/js/types/api-generated.ts
@@ -781,98 +781,6 @@ export interface paths {
*/
get: operations["get_plugins"];
};
- "/roles": {
- /**
- * Get a list of roles.
- *
- * *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- */
- get: operations["get_roles"];
- /**
- * Create a new role.
- *
- * *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- */
- post: operations["post_role"];
- };
- "/roles/{role_name}": {
- /**
- * Get a role.
- *
- * *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- */
- get: operations["get_role"];
- /**
- * Delete a role.
- *
- * *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- */
- delete: operations["delete_role"];
- /**
- * Update a role.
- *
- * *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- */
- patch: operations["patch_role"];
- parameters: {
- path: {
- /** The role name */
- role_name: components["parameters"]["RoleName"];
- };
- };
- };
- "/permissions": {
- /**
- * Get a list of permissions.
- *
- * *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- */
- get: operations["get_permissions"];
- };
- "/users": {
- /**
- * Get a list of users.
- *
- * *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- */
- get: operations["get_users"];
- /**
- * Create a new user with unique username and email.
- *
- * *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- */
- post: operations["post_user"];
- };
- "/users/{username}": {
- /**
- * Get a user with a specific username.
- *
- * *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- */
- get: operations["get_user"];
- /**
- * Delete a user with a specific username.
- *
- * *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- */
- delete: operations["delete_user"];
- /**
- * Update fields for a user.
- *
- * *This API endpoint is deprecated, please use the endpoint
`/auth/fab/v1` for this operation instead.*
- */
- patch: operations["patch_user"];
- parameters: {
- path: {
- /**
- * The username of the user.
- *
- * *New in version 2.1.0*
- */
- username: components["parameters"]["Username"];
- };
- };
- };
}
export interface components {
@@ -5123,318 +5031,6 @@ export interface operations {
404: components["responses"]["NotFound"];
};
};
- /**
- * Get a list of roles.
- *
- * *This API endpoint is deprecated, please use the endpoint `/auth/fab/v1`
for this operation instead.*
- */
- get_roles: {
- parameters: {
- query: {
- /** The numbers of items to return. */
- limit?: components["parameters"]["PageLimit"];
- /** The number of items to skip before starting to collect the result
set. */
- offset?: components["parameters"]["PageOffset"];
- /**
- * The name of the field to order the results by.
- * Prefix a field name with `-` to reverse the sort order.
- *
- * *New in version 2.1.0*
- */
- order_by?: components["parameters"]["OrderBy"];
- };
- };
- responses: {
- /** Success. */
- 200: {
- content: {
- "application/json": components["schemas"]["RoleCollection"];
- };
- };
- 401: components["responses"]["Unauthenticated"];
- 403: components["responses"]["PermissionDenied"];
- };
- };
- /**
- * Create a new role.
- *
- * *This API endpoint is deprecated, please use the endpoint `/auth/fab/v1`
for this operation instead.*
- */
- post_role: {
- responses: {
- /** Success. */
- 200: {
- content: {
- "application/json": components["schemas"]["Role"];
- };
- };
- 400: components["responses"]["BadRequest"];
- 401: components["responses"]["Unauthenticated"];
- 403: components["responses"]["PermissionDenied"];
- };
- requestBody: {
- content: {
- "application/json": components["schemas"]["Role"];
- };
- };
- };
- /**
- * Get a role.
- *
- * *This API endpoint is deprecated, please use the endpoint `/auth/fab/v1`
for this operation instead.*
- */
- get_role: {
- parameters: {
- path: {
- /** The role name */
- role_name: components["parameters"]["RoleName"];
- };
- };
- responses: {
- /** Success. */
- 200: {
- content: {
- "application/json": components["schemas"]["Role"];
- };
- };
- 401: components["responses"]["Unauthenticated"];
- 403: components["responses"]["PermissionDenied"];
- 404: components["responses"]["NotFound"];
- };
- };
- /**
- * Delete a role.
- *
- * *This API endpoint is deprecated, please use the endpoint `/auth/fab/v1`
for this operation instead.*
- */
- delete_role: {
- parameters: {
- path: {
- /** The role name */
- role_name: components["parameters"]["RoleName"];
- };
- };
- responses: {
- /** Success. */
- 204: never;
- 400: components["responses"]["BadRequest"];
- 401: components["responses"]["Unauthenticated"];
- 403: components["responses"]["PermissionDenied"];
- 404: components["responses"]["NotFound"];
- };
- };
- /**
- * Update a role.
- *
- * *This API endpoint is deprecated, please use the endpoint `/auth/fab/v1`
for this operation instead.*
- */
- patch_role: {
- parameters: {
- path: {
- /** The role name */
- role_name: components["parameters"]["RoleName"];
- };
- query: {
- /**
- * The fields to update on the resource. If absent or empty, all
modifiable fields are updated.
- * A comma-separated list of fully qualified names of fields.
- */
- update_mask?: components["parameters"]["UpdateMask"];
- };
- };
- responses: {
- /** Success. */
- 200: {
- content: {
- "application/json": components["schemas"]["Role"];
- };
- };
- 400: components["responses"]["BadRequest"];
- 401: components["responses"]["Unauthenticated"];
- 403: components["responses"]["PermissionDenied"];
- 404: components["responses"]["NotFound"];
- };
- requestBody: {
- content: {
- "application/json": components["schemas"]["Role"];
- };
- };
- };
- /**
- * Get a list of permissions.
- *
- * *This API endpoint is deprecated, please use the endpoint `/auth/fab/v1`
for this operation instead.*
- */
- get_permissions: {
- parameters: {
- query: {
- /** The numbers of items to return. */
- limit?: components["parameters"]["PageLimit"];
- /** The number of items to skip before starting to collect the result
set. */
- offset?: components["parameters"]["PageOffset"];
- };
- };
- responses: {
- /** Success. */
- 200: {
- content: {
- "application/json": components["schemas"]["ActionCollection"];
- };
- };
- 401: components["responses"]["Unauthenticated"];
- 403: components["responses"]["PermissionDenied"];
- };
- };
- /**
- * Get a list of users.
- *
- * *This API endpoint is deprecated, please use the endpoint `/auth/fab/v1`
for this operation instead.*
- */
- get_users: {
- parameters: {
- query: {
- /** The numbers of items to return. */
- limit?: components["parameters"]["PageLimit"];
- /** The number of items to skip before starting to collect the result
set. */
- offset?: components["parameters"]["PageOffset"];
- /**
- * The name of the field to order the results by.
- * Prefix a field name with `-` to reverse the sort order.
- *
- * *New in version 2.1.0*
- */
- order_by?: components["parameters"]["OrderBy"];
- };
- };
- responses: {
- /** Success. */
- 200: {
- content: {
- "application/json": components["schemas"]["UserCollection"];
- };
- };
- 401: components["responses"]["Unauthenticated"];
- 403: components["responses"]["PermissionDenied"];
- };
- };
- /**
- * Create a new user with unique username and email.
- *
- * *This API endpoint is deprecated, please use the endpoint `/auth/fab/v1`
for this operation instead.*
- */
- post_user: {
- responses: {
- /** Success. */
- 200: {
- content: {
- "application/json": components["schemas"]["User"];
- };
- };
- 400: components["responses"]["BadRequest"];
- 401: components["responses"]["Unauthenticated"];
- 403: components["responses"]["PermissionDenied"];
- 409: components["responses"]["AlreadyExists"];
- };
- requestBody: {
- content: {
- "application/json": components["schemas"]["User"];
- };
- };
- };
- /**
- * Get a user with a specific username.
- *
- * *This API endpoint is deprecated, please use the endpoint `/auth/fab/v1`
for this operation instead.*
- */
- get_user: {
- parameters: {
- path: {
- /**
- * The username of the user.
- *
- * *New in version 2.1.0*
- */
- username: components["parameters"]["Username"];
- };
- };
- responses: {
- /** Success. */
- 200: {
- content: {
- "application/json": components["schemas"]["UserCollectionItem"];
- };
- };
- 401: components["responses"]["Unauthenticated"];
- 403: components["responses"]["PermissionDenied"];
- 404: components["responses"]["NotFound"];
- };
- };
- /**
- * Delete a user with a specific username.
- *
- * *This API endpoint is deprecated, please use the endpoint `/auth/fab/v1`
for this operation instead.*
- */
- delete_user: {
- parameters: {
- path: {
- /**
- * The username of the user.
- *
- * *New in version 2.1.0*
- */
- username: components["parameters"]["Username"];
- };
- };
- responses: {
- /** Success. */
- 204: never;
- 400: components["responses"]["BadRequest"];
- 401: components["responses"]["Unauthenticated"];
- 403: components["responses"]["PermissionDenied"];
- 404: components["responses"]["NotFound"];
- };
- };
- /**
- * Update fields for a user.
- *
- * *This API endpoint is deprecated, please use the endpoint `/auth/fab/v1`
for this operation instead.*
- */
- patch_user: {
- parameters: {
- path: {
- /**
- * The username of the user.
- *
- * *New in version 2.1.0*
- */
- username: components["parameters"]["Username"];
- };
- query: {
- /**
- * The fields to update on the resource. If absent or empty, all
modifiable fields are updated.
- * A comma-separated list of fully qualified names of fields.
- */
- update_mask?: components["parameters"]["UpdateMask"];
- };
- };
- responses: {
- /** Success. */
- 200: {
- content: {
- "application/json": components["schemas"]["UserCollectionItem"];
- };
- };
- 400: components["responses"]["BadRequest"];
- 401: components["responses"]["Unauthenticated"];
- 403: components["responses"]["PermissionDenied"];
- 404: components["responses"]["NotFound"];
- };
- requestBody: {
- content: {
- "application/json": components["schemas"]["User"];
- };
- };
- };
}
export interface external {}
@@ -5970,40 +5566,3 @@ export type GetValueVariables = CamelCasedPropertiesDeep<
export type GetPluginsVariables = CamelCasedPropertiesDeep<
operations["get_plugins"]["parameters"]["query"]
>;
-export type GetRolesVariables = CamelCasedPropertiesDeep<
- operations["get_roles"]["parameters"]["query"]
->;
-export type PostRoleVariables = CamelCasedPropertiesDeep<
- operations["post_role"]["requestBody"]["content"]["application/json"]
->;
-export type GetRoleVariables = CamelCasedPropertiesDeep<
- operations["get_role"]["parameters"]["path"]
->;
-export type DeleteRoleVariables = CamelCasedPropertiesDeep<
- operations["delete_role"]["parameters"]["path"]
->;
-export type PatchRoleVariables = CamelCasedPropertiesDeep<
- operations["patch_role"]["parameters"]["path"] &
- operations["patch_role"]["parameters"]["query"] &
- operations["patch_role"]["requestBody"]["content"]["application/json"]
->;
-export type GetPermissionsVariables = CamelCasedPropertiesDeep<
- operations["get_permissions"]["parameters"]["query"]
->;
-export type GetUsersVariables = CamelCasedPropertiesDeep<
- operations["get_users"]["parameters"]["query"]
->;
-export type PostUserVariables = CamelCasedPropertiesDeep<
- operations["post_user"]["requestBody"]["content"]["application/json"]
->;
-export type GetUserVariables = CamelCasedPropertiesDeep<
- operations["get_user"]["parameters"]["path"]
->;
-export type DeleteUserVariables = CamelCasedPropertiesDeep<
- operations["delete_user"]["parameters"]["path"]
->;
-export type PatchUserVariables = CamelCasedPropertiesDeep<
- operations["patch_user"]["parameters"]["path"] &
- operations["patch_user"]["parameters"]["query"] &
- operations["patch_user"]["requestBody"]["content"]["application/json"]
->;
diff --git a/airflow/www/utils.py b/airflow/www/utils.py
index ef057adbf3..981dc030a2 100644
--- a/airflow/www/utils.py
+++ b/airflow/www/utils.py
@@ -61,8 +61,6 @@ if TYPE_CHECKING:
from sqlalchemy.sql import Select
from sqlalchemy.sql.operators import ColumnOperators
- from airflow.www.extensions.init_appbuilder import AirflowAppBuilder
-
TI = TaskInstance
@@ -924,21 +922,16 @@ class UIAlert:
self.html = html
self.message = Markup(message) if html else message
- def should_show(self, appbuilder: AirflowAppBuilder) -> bool:
+ def should_show(self) -> bool:
"""
Determine if the user should see the message.
- The decision is based on the user's role. If ``AUTH_ROLE_PUBLIC`` is
- set in ``webserver_config.py``, An anonymous user would have the
- ``AUTH_ROLE_PUBLIC`` role.
+ The decision is based on the user's role.
"""
if self.roles:
current_user = get_auth_manager().get_user()
if current_user is not None:
user_roles = {r.name for r in getattr(current_user, "roles",
[])}
- elif "AUTH_ROLE_PUBLIC" in appbuilder.get_app.config:
- # If the current_user is anonymous, assign AUTH_ROLE_PUBLIC
role (if it exists) to them
- user_roles = {appbuilder.get_app.config["AUTH_ROLE_PUBLIC"]}
else:
# Unable to obtain user role - default to not showing
return False
diff --git a/airflow/www/views.py b/airflow/www/views.py
index 65c677c9e3..0ef37f71d3 100644
--- a/airflow/www/views.py
+++ b/airflow/www/views.py
@@ -1093,9 +1093,7 @@ class Airflow(AirflowBaseView):
section="webserver", key="instance_name_has_markup", fallback=False
)
- dashboard_alerts = [
- fm for fm in settings.DASHBOARD_UIALERTS if
fm.should_show(get_airflow_app().appbuilder)
- ]
+ dashboard_alerts = [fm for fm in settings.DASHBOARD_UIALERTS if
fm.should_show()]
def _iter_parsed_moved_data_table_names():
for table_name in inspect(session.get_bind()).get_table_names():
diff --git a/newsfragments/42280.significant.rst
b/newsfragments/42280.significant.rst
new file mode 100644
index 0000000000..00d80d259b
--- /dev/null
+++ b/newsfragments/42280.significant.rst
@@ -0,0 +1,5 @@
+Removed deprecated Rest API endpoints:
+
+* /api/v1/roles. Use /auth/fab/v1/roles instead
+* /api/v1/permissions. Use /auth/fab/v1/permissions instead
+* /api/v1/users. Use /auth/fab/v1/users instead
diff --git a/tests/api_connexion/conftest.py b/tests/api_connexion/conftest.py
index df0c3462f5..38e7b58cb5 100644
--- a/tests/api_connexion/conftest.py
+++ b/tests/api_connexion/conftest.py
@@ -58,14 +58,3 @@ def dagbag():
DagBag(include_examples=True, read_dags_from_db=False).sync_to_db()
return DagBag(include_examples=True, read_dags_from_db=True)
-
-
[email protected]
-def set_auto_role_public(request):
- app = request.getfixturevalue("minimal_app_for_api")
- auto_role_public = app.config["AUTH_ROLE_PUBLIC"]
- app.config["AUTH_ROLE_PUBLIC"] = request.param
-
- yield
-
- app.config["AUTH_ROLE_PUBLIC"] = auto_role_public
diff --git a/tests/api_connexion/endpoints/test_config_endpoint.py
b/tests/api_connexion/endpoints/test_config_endpoint.py
index 42d0922de8..475753a4a9 100644
--- a/tests/api_connexion/endpoints/test_config_endpoint.py
+++ b/tests/api_connexion/endpoints/test_config_endpoint.py
@@ -225,16 +225,6 @@ class TestGetConfig:
assert response.status_code == 403
assert "chose not to expose" in response.json["detail"]
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code):
- response = self.client.get("/api/v1/config", headers={"Accept":
"application/json"})
-
- assert response.status_code == expected_status_code
-
class TestGetValue:
@pytest.fixture(autouse=True)
@@ -352,15 +342,3 @@ class TestGetValue:
)
assert response.status_code == 403
assert "chose not to expose" in response.json["detail"]
-
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code):
- response = self.client.get(
- "/api/v1/config/section/smtp/option/smtp_mail_from",
headers={"Accept": "application/json"}
- )
-
- assert response.status_code == expected_status_code
diff --git a/tests/api_connexion/endpoints/test_connection_endpoint.py
b/tests/api_connexion/endpoints/test_connection_endpoint.py
index 75a745c76d..a19b046aa2 100644
--- a/tests/api_connexion/endpoints/test_connection_endpoint.py
+++ b/tests/api_connexion/endpoints/test_connection_endpoint.py
@@ -112,22 +112,6 @@ class TestDeleteConnection(TestConnectionEndpoint):
)
assert response.status_code == 403
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 204)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, session):
- connection_model = Connection(conn_id="test-connection",
conn_type="test_type")
- session.add(connection_model)
- session.commit()
- conn = session.query(Connection).all()
- assert len(conn) == 1
-
- response = self.client.delete("/api/v1/connections/test-connection")
-
- assert response.status_code == expected_status_code
-
class TestGetConnection(TestConnectionEndpoint):
def test_should_respond_200(self, session):
@@ -194,31 +178,6 @@ class TestGetConnection(TestConnectionEndpoint):
assert_401(response)
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, session):
- connection_model = Connection(
- conn_id="test-connection-id",
- conn_type="mysql",
- description="test description",
- host="mysql",
- login="login",
- schema="testschema",
- port=80,
- extra='{"param": "value"}',
- )
- session.add(connection_model)
- session.commit()
- result = session.query(Connection).all()
- assert len(result) == 1
-
- response = self.client.get("/api/v1/connections/test-connection-id")
-
- assert response.status_code == expected_status_code
-
class TestGetConnections(TestConnectionEndpoint):
def test_should_respond_200(self, session):
@@ -297,16 +256,6 @@ class TestGetConnections(TestConnectionEndpoint):
assert_401(response)
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code):
- response = self.client.get("/api/v1/connections")
-
- assert response.status_code == expected_status_code
-
class TestGetConnectionsPagination(TestConnectionEndpoint):
@pytest.mark.parametrize(
@@ -580,21 +529,6 @@ class TestPatchConnection(TestConnectionEndpoint):
assert_401(response)
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, session):
- self._create_connection(session)
-
- response = self.client.patch(
- "/api/v1/connections/test-connection-id",
- json={"connection_id": "test-connection-id", "conn_type":
"test_type", "extra": '{"key": "var"}'},
- )
-
- assert response.status_code == expected_status_code
-
class TestPostConnection(TestConnectionEndpoint):
def test_post_should_respond_200(self, session):
@@ -676,18 +610,6 @@ class TestPostConnection(TestConnectionEndpoint):
assert_401(response)
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code):
- response = self.client.post(
- "/api/v1/connections", json={"connection_id":
"test-connection-id", "conn_type": "test_type"}
- )
-
- assert response.status_code == expected_status_code
-
class TestConnection(TestConnectionEndpoint):
@mock.patch.dict(os.environ, {"AIRFLOW__CORE__TEST_CONNECTION": "Enabled"})
@@ -741,14 +663,3 @@ class TestConnection(TestConnectionEndpoint):
"Testing connections is disabled in Airflow configuration. "
"Contact your deployment admin to enable it."
)
-
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- @mock.patch.dict(os.environ, {"AIRFLOW__CORE__TEST_CONNECTION": "Enabled"})
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code):
- payload = {"connection_id": "test-connection-id", "conn_type":
"sqlite"}
- response = self.client.post("/api/v1/connections/test", json=payload)
- assert response.status_code == expected_status_code
diff --git a/tests/api_connexion/endpoints/test_dag_endpoint.py
b/tests/api_connexion/endpoints/test_dag_endpoint.py
index 4268d4ea19..9905b4e27a 100644
--- a/tests/api_connexion/endpoints/test_dag_endpoint.py
+++ b/tests/api_connexion/endpoints/test_dag_endpoint.py
@@ -322,24 +322,6 @@ class TestGetDag(TestDagEndpoint):
)
assert response.status_code == 400, f"Current code:
{response.status_code}"
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, session):
- dag_model = DagModel(
- dag_id="TEST_DAG_1",
- fileloc="/tmp/dag_1.py",
- timetable_summary=None,
- is_paused=False,
- )
- session.add(dag_model)
- session.commit()
-
- response = self.client.get("/api/v1/dags/TEST_DAG_1")
- assert response.status_code == expected_status_code
-
class TestGetDagDetails(TestDagEndpoint):
def test_should_respond_200(self, url_safe_serializer):
@@ -739,18 +721,6 @@ class TestGetDagDetails(TestDagEndpoint):
)
assert response.status_code == 400, f"Current code:
{response.status_code}"
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, url_safe_serializer):
- self._create_dag_model_for_details_endpoint(self.dag_id)
- url_safe_serializer.dumps("/tmp/dag.py")
- response = self.client.get(f"/api/v1/dags/{self.dag_id}/details")
-
- assert response.status_code == expected_status_code
-
class TestGetDags(TestDagEndpoint):
@provide_session
@@ -1237,22 +1207,6 @@ class TestGetDags(TestDagEndpoint):
assert response.status_code == 400, f"Current code:
{response.status_code}"
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, session):
- self._create_dag_models(2)
- self._create_deactivated_dag()
-
- dags_query = session.query(DagModel)
- assert len(dags_query.all()) == 3
-
- response = self.client.get("api/v1/dags")
-
- assert response.status_code == expected_status_code
-
class TestPatchDag(TestDagEndpoint):
def test_should_respond_200_on_patch_is_paused(self, url_safe_serializer,
session):
@@ -1466,24 +1420,6 @@ class TestPatchDag(TestDagEndpoint):
assert response.status_code == 403
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(
- self, set_auto_role_public, expected_status_code, url_safe_serializer,
session
- ):
- url_safe_serializer.dumps("/tmp/dag_1.py")
- dag_model = self._create_dag_model()
- payload = {"is_paused": False}
- response = self.client.patch(
- f"/api/v1/dags/{dag_model.dag_id}",
- json=payload,
- )
-
- assert response.status_code == expected_status_code
-
class TestPatchDags(TestDagEndpoint):
@provide_session
@@ -2225,29 +2161,6 @@ class TestPatchDags(TestDagEndpoint):
)
assert response.status_code == 400
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(
- self, set_auto_role_public, expected_status_code, session,
url_safe_serializer
- ):
- url_safe_serializer.dumps("/tmp/dag_1.py")
- url_safe_serializer.dumps("/tmp/dag_2.py")
- self._create_dag_models(2)
- self._create_deactivated_dag()
-
- dags_query = session.query(DagModel)
- assert len(dags_query.all()) == 3
-
- response = self.client.patch(
- "/api/v1/dags?dag_id_pattern=~",
- json={"is_paused": False},
- )
-
- assert response.status_code == expected_status_code
-
class TestDeleteDagEndpoint(TestDagEndpoint):
def test_that_dag_can_be_deleted(self, session):
@@ -2299,15 +2212,3 @@ class TestDeleteDagEndpoint(TestDagEndpoint):
environ_overrides={"REMOTE_USER": "test_no_permissions"},
)
assert response.status_code == 403
-
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 204)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code):
- self._create_dag_models(1)
-
- response = self.client.delete("/api/v1/dags/TEST_DAG_1")
-
- assert response.status_code == expected_status_code
diff --git a/tests/api_connexion/endpoints/test_dag_run_endpoint.py
b/tests/api_connexion/endpoints/test_dag_run_endpoint.py
index 31a356ce53..deb5fe0af2 100644
--- a/tests/api_connexion/endpoints/test_dag_run_endpoint.py
+++ b/tests/api_connexion/endpoints/test_dag_run_endpoint.py
@@ -239,18 +239,6 @@ class TestDeleteDagRun(TestDagRunEndpoint):
)
assert response.status_code == 403
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 204)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, session):
- session.add_all(self._create_test_dag_run())
- session.commit()
- response =
self.client.delete("api/v1/dags/TEST_DAG_ID/dagRuns/TEST_DAG_RUN_ID_1")
-
- assert response.status_code == expected_status_code
-
class TestGetDagRun(TestDagRunEndpoint):
def test_should_respond_200(self, session):
@@ -374,29 +362,6 @@ class TestGetDagRun(TestDagRunEndpoint):
)
assert response.status_code == 400, f"Current code:
{response.status_code}"
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, session):
- dagrun_model = DagRun(
- dag_id="TEST_DAG_ID",
- run_id="TEST_DAG_RUN_ID",
- run_type=DagRunType.MANUAL,
- execution_date=timezone.parse(self.default_time),
- start_date=timezone.parse(self.default_time),
- external_trigger=True,
- state="running",
- )
- session.add(dagrun_model)
- session.commit()
- result = session.query(DagRun).all()
- assert len(result) == 1
-
- response =
self.client.get("api/v1/dags/TEST_DAG_ID/dagRuns/TEST_DAG_RUN_ID")
- assert response.status_code == expected_status_code
-
class TestGetDagRuns(TestDagRunEndpoint):
def test_should_respond_200(self, session):
@@ -581,18 +546,6 @@ class TestGetDagRuns(TestDagRunEndpoint):
)
assert response.status_code == 400, f"Current code:
{response.status_code}"
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, session):
- self._create_test_dag_run()
- result = session.query(DagRun).all()
- assert len(result) == 2
- response = self.client.get("api/v1/dags/TEST_DAG_ID/dagRuns")
- assert response.status_code == expected_status_code
-
class TestGetDagRunsPagination(TestDagRunEndpoint):
@pytest.mark.parametrize(
@@ -1032,18 +985,6 @@ class TestGetDagRunBatch(TestDagRunEndpoint):
assert_401(response)
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code):
- self._create_test_dag_run()
-
- response = self.client.post("api/v1/dags/~/dagRuns/list",
json={"dag_ids": ["TEST_DAG_ID"]})
-
- assert response.status_code == expected_status_code
-
class TestGetDagRunBatchPagination(TestDagRunEndpoint):
@pytest.mark.parametrize(
@@ -1702,26 +1643,6 @@ class TestPostDagRun(TestDagRunEndpoint):
)
assert response.status_code == 403
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code):
- execution_date = "2020-11-10T08:25:56.939143+00:00"
- logical_date = "2020-11-10T08:25:56.939143+00:00"
- self._create_dag("TEST_DAG_ID")
-
- response = self.client.post(
- "api/v1/dags/TEST_DAG_ID/dagRuns",
- json={
- "execution_date": execution_date,
- "logical_date": logical_date,
- },
- )
-
- assert response.status_code == expected_status_code
-
class TestPatchDagRunState(TestDagRunEndpoint):
@pytest.mark.parametrize("state", ["failed", "success", "queued"])
@@ -1848,31 +1769,6 @@ class TestPatchDagRunState(TestDagRunEndpoint):
)
assert response.status_code == 404
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, dag_maker, session):
- dag_id = "TEST_DAG_ID"
- dag_run_id = "TEST_DAG_RUN_ID"
- with dag_maker(dag_id) as dag:
- task = EmptyOperator(task_id="task_id", dag=dag)
- self.app.dag_bag.bag_dag(dag)
- dr = dag_maker.create_dagrun(run_id=dag_run_id,
run_type=DagRunType.SCHEDULED)
- ti = dr.get_task_instance(task_id="task_id")
- ti.task = task
- ti.state = State.RUNNING
- session.merge(ti)
- session.commit()
-
- response = self.client.patch(
- f"api/v1/dags/{dag_id}/dagRuns/{dag_run_id}",
- json={"state": "failed"},
- )
-
- assert response.status_code == expected_status_code
-
class TestClearDagRun(TestDagRunEndpoint):
def test_should_respond_200(self, dag_maker, session):
@@ -2011,31 +1907,6 @@ class TestClearDagRun(TestDagRunEndpoint):
)
assert response.status_code == 404
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, dag_maker, session):
- dag_id = "TEST_DAG_ID"
- dag_run_id = "TEST_DAG_RUN_ID"
- with dag_maker(dag_id) as dag:
- task = EmptyOperator(task_id="task_id", dag=dag)
- self.app.dag_bag.bag_dag(dag)
- dr = dag_maker.create_dagrun(run_id=dag_run_id,
run_type=DagRunType.SCHEDULED)
- ti = dr.get_task_instance(task_id="task_id")
- ti.task = task
- ti.state = State.RUNNING
- session.merge(ti)
- session.commit()
-
- response = self.client.patch(
- f"api/v1/dags/{dag_id}/dagRuns/{dag_run_id}",
- json={"state": "failed"},
- )
-
- assert response.status_code == expected_status_code
-
@pytest.mark.need_serialized_dag
class TestGetDagRunDatasetTriggerEvents(TestDagRunEndpoint):
@@ -2130,42 +2001,6 @@ class
TestGetDagRunDatasetTriggerEvents(TestDagRunEndpoint):
assert_401(response)
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, dag_maker, session):
- dataset1 = Dataset(uri="ds1")
-
- with dag_maker(dag_id="source_dag", start_date=timezone.utcnow(),
session=session):
- EmptyOperator(task_id="task", outlets=[dataset1])
- dr = dag_maker.create_dagrun()
- ti = dr.task_instances[0]
-
- ds1_id =
session.query(DatasetModel.id).filter_by(uri=dataset1.uri).scalar()
- event = DatasetEvent(
- dataset_id=ds1_id,
- source_task_id=ti.task_id,
- source_dag_id=ti.dag_id,
- source_run_id=ti.run_id,
- source_map_index=ti.map_index,
- )
- session.add(event)
-
- with dag_maker(dag_id="TEST_DAG_ID", start_date=timezone.utcnow(),
session=session):
- pass
- dr = dag_maker.create_dagrun(run_id="TEST_DAG_RUN_ID",
run_type=DagRunType.DATASET_TRIGGERED)
- dr.consumed_dataset_events.append(event)
-
- session.commit()
- assert event.timestamp
-
- response = self.client.get(
-
"api/v1/dags/TEST_DAG_ID/dagRuns/TEST_DAG_RUN_ID/upstreamDatasetEvents",
- )
- assert response.status_code == expected_status_code
-
class TestSetDagRunNote(TestDagRunEndpoint):
def test_should_respond_200(self, dag_maker, session):
@@ -2282,23 +2117,3 @@ class TestSetDagRunNote(TestDagRunEndpoint):
environ_overrides={"REMOTE_USER": "test"},
)
assert response.status_code == 404
-
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, session):
- dag_runs: list[DagRun] = self._create_test_dag_run(DagRunState.SUCCESS)
- session.add_all(dag_runs)
- session.commit()
- created_dr: DagRun = dag_runs[0]
- new_note_value = "My super cool DagRun notes"
- response = self.client.patch(
-
f"api/v1/dags/{created_dr.dag_id}/dagRuns/{created_dr.run_id}/setNote",
- json={"note": new_note_value},
- )
-
- session.query(DagRun).filter(DagRun.run_id ==
created_dr.run_id).first()
-
- assert response.status_code == expected_status_code
diff --git a/tests/api_connexion/endpoints/test_dag_source_endpoint.py
b/tests/api_connexion/endpoints/test_dag_source_endpoint.py
index ee3471b904..1e5389d377 100644
--- a/tests/api_connexion/endpoints/test_dag_source_endpoint.py
+++ b/tests/api_connexion/endpoints/test_dag_source_endpoint.py
@@ -202,19 +202,3 @@ class TestGetSource:
)
assert response.status_code == 403
assert read_dag.status_code == 200
-
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, url_safe_serializer):
- dagbag = DagBag(dag_folder=EXAMPLE_DAG_FILE)
- dagbag.sync_to_db()
- test_dag: DAG = dagbag.dags[TEST_DAG_ID]
- self._get_dag_file_docstring(test_dag.fileloc)
-
- url =
f"/api/v1/dagSources/{url_safe_serializer.dumps(test_dag.fileloc)}"
- response = self.client.get(url, headers={"Accept": "text/plain"})
-
- assert response.status_code == expected_status_code
diff --git a/tests/api_connexion/endpoints/test_dag_warning_endpoint.py
b/tests/api_connexion/endpoints/test_dag_warning_endpoint.py
index 5e0730ed13..3e7c805173 100644
--- a/tests/api_connexion/endpoints/test_dag_warning_endpoint.py
+++ b/tests/api_connexion/endpoints/test_dag_warning_endpoint.py
@@ -170,15 +170,3 @@ class TestGetDagWarningEndpoint(TestBaseDagWarning):
query_string={"dag_id": "dag1"},
)
assert response.status_code == 403
-
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code):
- response = self.client.get(
- "/api/v1/dagWarnings",
- query_string={"dag_id": "dag1", "warning_type": "non-existent
pool"},
- )
- assert response.status_code == expected_status_code
diff --git a/tests/api_connexion/endpoints/test_dataset_endpoint.py
b/tests/api_connexion/endpoints/test_dataset_endpoint.py
index fb94b0ad9f..25f8012039 100644
--- a/tests/api_connexion/endpoints/test_dataset_endpoint.py
+++ b/tests/api_connexion/endpoints/test_dataset_endpoint.py
@@ -144,22 +144,6 @@ class TestGetDatasetEndpoint(TestDatasetEndpoint):
response =
self.client.get(f"/api/v1/datasets/{urllib.parse.quote('s3://bucket/key',
safe='')}")
assert_401(response)
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, session):
- self._create_dataset(session)
- assert session.query(DatasetModel).count() == 1
-
- with assert_queries_count(5):
- response = self.client.get(
- f"/api/v1/datasets/{urllib.parse.quote('s3://bucket/key',
safe='')}",
- )
-
- assert response.status_code == expected_status_code
-
class TestGetDatasets(TestDatasetEndpoint):
def test_should_respond_200(self, session):
@@ -332,31 +316,6 @@ class TestGetDatasets(TestDatasetEndpoint):
response_data = response.json
assert len(response_data["datasets"]) == expected_num
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, session):
- datasets = [
- DatasetModel(
- id=i,
- uri=f"s3://bucket/key/{i}",
- extra={"foo": "bar"},
- created_at=timezone.parse(self.default_time),
- updated_at=timezone.parse(self.default_time),
- )
- for i in [1, 2]
- ]
- session.add_all(datasets)
- session.commit()
- assert session.query(DatasetModel).count() == 2
-
- with assert_queries_count(8):
- response = self.client.get("/api/v1/datasets")
-
- assert response.status_code == expected_status_code
-
class TestGetDatasetsEndpointPagination(TestDatasetEndpoint):
@pytest.mark.parametrize(
@@ -623,32 +582,6 @@ class TestGetDatasetEvents(TestDatasetEndpoint):
"total_entries": 1,
}
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, session):
- self._create_dataset(session)
- common = {
- "dataset_id": 1,
- "extra": {"foo": "bar"},
- "source_dag_id": "foo",
- "source_task_id": "bar",
- "source_run_id": "custom",
- "source_map_index": -1,
- "created_dagruns": [],
- }
-
- events = [DatasetEvent(id=i,
timestamp=timezone.parse(self.default_time), **common) for i in [1, 2]]
- session.add_all(events)
- session.commit()
- assert session.query(DatasetEvent).count() == 2
-
- response = self.client.get("/api/v1/datasets/events")
-
- assert response.status_code == expected_status_code
-
class TestPostDatasetEvents(TestDatasetEndpoint):
@pytest.fixture
@@ -721,19 +654,6 @@ class TestPostDatasetEvents(TestDatasetEndpoint):
response = self.client.post("/api/v1/datasets/events",
json={"dataset_uri": "TEST_DATASET_URI"})
assert_401(response)
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- @pytest.mark.usefixtures("time_freezer")
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, session):
- self._create_dataset(session)
- event_payload = {"dataset_uri": "s3://bucket/key", "extra": {"foo":
"bar"}}
- response = self.client.post("/api/v1/datasets/events",
json=event_payload)
-
- assert response.status_code == expected_status_code
-
class TestGetDatasetEventsEndpointPagination(TestDatasetEndpoint):
@pytest.mark.parametrize(
@@ -904,27 +824,6 @@ class
TestGetDagDatasetQueuedEvent(TestQueuedEventEndpoint):
assert response.status_code == 403
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- @pytest.mark.usefixtures("time_freezer")
- def test_with_auth_role_public_set(
- self, set_auto_role_public, expected_status_code, create_dummy_dag,
session
- ):
- dag, _ = create_dummy_dag()
- dag_id = dag.dag_id
- dataset_id = self._create_dataset(session).id
- self._create_dataset_dag_run_queues(dag_id, dataset_id, session)
- dataset_uri = "s3://bucket/key"
-
- response = self.client.get(
- f"/api/v1/dags/{dag_id}/datasets/queuedEvent/{dataset_uri}",
- )
-
- assert response.status_code == expected_status_code
-
class TestDeleteDagDatasetQueuedEvent(TestDatasetEndpoint):
def test_delete_should_respond_204(self, session, create_dummy_dag):
@@ -1042,24 +941,6 @@ class
TestGetDagDatasetQueuedEvents(TestQueuedEventEndpoint):
assert response.status_code == 403
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(
- self, set_auto_role_public, expected_status_code, session,
create_dummy_dag
- ):
- dag, _ = create_dummy_dag()
- dag_id = dag.dag_id
- dataset_id = self._create_dataset(session).id
- self._create_dataset_dag_run_queues(dag_id, dataset_id, session)
-
- response = self.client.get(
- f"/api/v1/dags/{dag_id}/datasets/queuedEvent",
- )
- assert response.status_code == expected_status_code
-
class TestDeleteDagDatasetQueuedEvents(TestDatasetEndpoint):
def test_should_respond_404(self):
@@ -1095,31 +976,6 @@ class
TestDeleteDagDatasetQueuedEvents(TestDatasetEndpoint):
assert response.status_code == 403
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 204)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(
- self, set_auto_role_public, expected_status_code, session,
create_dummy_dag
- ):
- dag, _ = create_dummy_dag()
- dag_id = dag.dag_id
- dataset_uri = "s3://bucket/key"
- dataset_id = self._create_dataset(session).id
-
- ddrq = DatasetDagRunQueue(target_dag_id=dag_id, dataset_id=dataset_id)
- session.add(ddrq)
- session.commit()
- conn = session.query(DatasetDagRunQueue).all()
- assert len(conn) == 1
-
- response = self.client.delete(
- f"/api/v1/dags/{dag_id}/datasets/queuedEvent/{dataset_uri}",
- )
-
- assert response.status_code == expected_status_code
-
class TestGetDatasetQueuedEvents(TestQueuedEventEndpoint):
@pytest.mark.usefixtures("time_freezer")
@@ -1180,26 +1036,6 @@ class
TestGetDatasetQueuedEvents(TestQueuedEventEndpoint):
assert response.status_code == 403
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- @pytest.mark.usefixtures("time_freezer")
- def test_with_auth_role_public_set(
- self, set_auto_role_public, expected_status_code, session,
create_dummy_dag
- ):
- dag, _ = create_dummy_dag()
- dag_id = dag.dag_id
- dataset_id = self._create_dataset(session).id
- self._create_dataset_dag_run_queues(dag_id, dataset_id, session)
-
- response = self.client.get(
- f"/api/v1/dags/{dag_id}/datasets/queuedEvent",
- )
-
- assert response.status_code == expected_status_code
-
class TestDeleteDatasetQueuedEvents(TestQueuedEventEndpoint):
def test_delete_should_respond_204(self, session, create_dummy_dag):
@@ -1251,23 +1087,3 @@ class
TestDeleteDatasetQueuedEvents(TestQueuedEventEndpoint):
)
assert response.status_code == 403
-
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 204)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(
- self, set_auto_role_public, expected_status_code, session,
create_dummy_dag
- ):
- dag, _ = create_dummy_dag()
- dag_id = dag.dag_id
- dataset_id = self._create_dataset(session).id
- self._create_dataset_dag_run_queues(dag_id, dataset_id, session)
- dataset_uri = "s3://bucket/key"
-
- response = self.client.delete(
- f"/api/v1/datasets/queuedEvent/{dataset_uri}",
- )
-
- assert response.status_code == expected_status_code
diff --git a/tests/api_connexion/endpoints/test_event_log_endpoint.py
b/tests/api_connexion/endpoints/test_event_log_endpoint.py
index e6f4d23cea..0fdef1a3af 100644
--- a/tests/api_connexion/endpoints/test_event_log_endpoint.py
+++ b/tests/api_connexion/endpoints/test_event_log_endpoint.py
@@ -109,21 +109,6 @@ class TestEventLogEndpoint:
def teardown_method(self) -> None:
clear_db_logs()
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, log_model):
- event_log_id = log_model.id
- response = self.client.get(
- f"/api/v1/eventLogs/{event_log_id}",
environ_overrides={"REMOTE_USER": "test"}
- )
-
- response = self.client.get("/api/v1/eventLogs")
-
- assert response.status_code == expected_status_code
-
class TestGetEventLog(TestEventLogEndpoint):
def test_should_respond_200(self, log_model):
@@ -171,18 +156,6 @@ class TestGetEventLog(TestEventLogEndpoint):
)
assert response.status_code == 403
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code, log_model):
- event_log_id = log_model.id
-
- response = self.client.get(f"/api/v1/eventLogs/{event_log_id}")
-
- assert response.status_code == expected_status_code
-
class TestGetEventLogs(TestEventLogEndpoint):
def test_should_respond_200(self, session, create_log_model):
@@ -392,23 +365,6 @@ class TestGetEventLogs(TestEventLogEndpoint):
assert response_data["total_entries"] == 1
assert {"cli_scheduler"} == {x["event"] for x in
response_data["event_logs"]}
- @pytest.mark.parametrize(
- "set_auto_role_public, expected_status_code",
- (("Public", 403), ("Admin", 200)),
- indirect=["set_auto_role_public"],
- )
- def test_with_auth_role_public_set(
- self, set_auto_role_public, expected_status_code, create_log_model,
session
- ):
- log_model_3 = Log(event="cli_scheduler", owner="root",
extra='{"host_name": "e24b454f002a"}')
- log_model_3.dttm = self.default_time_2
-
- session.add(log_model_3)
- session.flush()
- response = self.client.get("/api/v1/eventLogs")
-
- assert response.status_code == expected_status_code
-
class TestGetEventLogPagination(TestEventLogEndpoint):
@pytest.mark.parametrize(
diff --git a/tests/api_connexion/endpoints/test_forward_to_fab_endpoint.py
b/tests/api_connexion/endpoints/test_forward_to_fab_endpoint.py
deleted file mode 100644
index 037e35914f..0000000000
--- a/tests/api_connexion/endpoints/test_forward_to_fab_endpoint.py
+++ /dev/null
@@ -1,238 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-from __future__ import annotations
-
-from unittest import mock
-
-import pytest
-
-from airflow.auth.managers.base_auth_manager import BaseAuthManager
-from airflow.providers.fab.auth_manager.models import Role, User
-from airflow.security import permissions
-from airflow.utils import timezone
-from airflow.utils.session import create_session
-from airflow.www.security_manager import EXISTING_ROLES
-from tests.test_utils.api_connexion_utils import create_role, create_user,
delete_role, delete_user
-
-pytestmark = [pytest.mark.db_test, pytest.mark.skip_if_database_isolation_mode]
-
-DEFAULT_TIME = "2020-06-11T18:00:00+00:00"
-
-EXAMPLE_USER_NAME = "example_user"
-
-EXAMPLE_USER_EMAIL = "[email protected]"
-
-
-def _delete_user(**filters):
- with create_session() as session:
- user = session.query(User).filter_by(**filters).first()
- if user is None:
- return
- user.roles = []
- session.delete(user)
-
-
[email protected]
-def autoclean_user_payload(autoclean_username, autoclean_email):
- return {
- "username": autoclean_username,
- "password": "resutsop",
- "email": autoclean_email,
- "first_name": "Tester",
- "last_name": "",
- }
-
-
[email protected]
-def autoclean_admin_user(configured_app, autoclean_user_payload):
- security_manager = configured_app.appbuilder.sm
- return security_manager.add_user(
- role=security_manager.find_role("Admin"),
- **autoclean_user_payload,
- )
-
-
[email protected]
-def autoclean_username():
- _delete_user(username=EXAMPLE_USER_NAME)
- yield EXAMPLE_USER_NAME
- _delete_user(username=EXAMPLE_USER_NAME)
-
-
[email protected]
-def autoclean_email():
- _delete_user(email=EXAMPLE_USER_EMAIL)
- yield EXAMPLE_USER_EMAIL
- _delete_user(email=EXAMPLE_USER_EMAIL)
-
-
[email protected](scope="module")
-def configured_app(minimal_app_for_api):
- app = minimal_app_for_api
- create_user(
- app, # type: ignore
- username="test",
- role_name="Test",
- permissions=[
- (permissions.ACTION_CAN_CREATE, permissions.RESOURCE_ROLE),
- (permissions.ACTION_CAN_READ, permissions.RESOURCE_ROLE),
- (permissions.ACTION_CAN_EDIT, permissions.RESOURCE_ROLE),
- (permissions.ACTION_CAN_DELETE, permissions.RESOURCE_ROLE),
- (permissions.ACTION_CAN_READ, permissions.RESOURCE_ACTION),
- (permissions.ACTION_CAN_CREATE, permissions.RESOURCE_USER),
- (permissions.ACTION_CAN_DELETE, permissions.RESOURCE_USER),
- (permissions.ACTION_CAN_EDIT, permissions.RESOURCE_USER),
- (permissions.ACTION_CAN_READ, permissions.RESOURCE_USER),
- ],
- )
-
- yield app
-
- delete_user(app, username="test") # type: ignore
-
-
-class TestFABforwarding:
- @pytest.fixture(autouse=True)
- def setup_attrs(self, configured_app) -> None:
- self.app = configured_app
- self.client = self.app.test_client() # type:ignore
-
- def teardown_method(self):
- """
- Delete all roles except these ones.
- Test and TestNoPermissions are deleted by delete_user above
- """
- session = self.app.appbuilder.get_session
- existing_roles = set(EXISTING_ROLES)
- existing_roles.update(["Test", "TestNoPermissions"])
- roles =
session.query(Role).filter(~Role.name.in_(existing_roles)).all()
- for role in roles:
- delete_role(self.app, role.name)
- users = session.query(User).filter(User.changed_on ==
timezone.parse(DEFAULT_TIME))
- users.delete(synchronize_session=False)
- session.commit()
-
-
-class TestFABRoleForwarding(TestFABforwarding):
-
@mock.patch("airflow.api_connexion.endpoints.forward_to_fab_endpoint.get_auth_manager")
- def test_raises_400_if_manager_is_not_fab(self, mock_get_auth_manager):
- mock_get_auth_manager.return_value =
BaseAuthManager(self.app.appbuilder)
- response = self.client.get("api/v1/roles",
environ_overrides={"REMOTE_USER": "test"})
- assert response.status_code == 400
- assert (
- response.json["detail"]
- == "This endpoint is only available when using the default auth
manager FabAuthManager."
- )
-
- def test_get_role_forwards_to_fab(self):
- resp = self.client.get("api/v1/roles/Test",
environ_overrides={"REMOTE_USER": "test"})
- assert resp.status_code == 200
-
- def test_get_roles_forwards_to_fab(self):
- resp = self.client.get("api/v1/roles",
environ_overrides={"REMOTE_USER": "test"})
- assert resp.status_code == 200
-
- def test_delete_role_forwards_to_fab(self):
- role = create_role(self.app, "mytestrole")
- resp = self.client.delete(f"api/v1/roles/{role.name}",
environ_overrides={"REMOTE_USER": "test"})
- assert resp.status_code == 204
-
- def test_patch_role_forwards_to_fab(self):
- role = create_role(self.app, "mytestrole")
- resp = self.client.patch(
- f"api/v1/roles/{role.name}", json={"name": "Test2"},
environ_overrides={"REMOTE_USER": "test"}
- )
- assert resp.status_code == 200
-
- def test_post_role_forwards_to_fab(self):
- payload = {
- "name": "Test2",
- "actions": [{"resource": {"name": "Connections"}, "action":
{"name": "can_create"}}],
- }
- resp = self.client.post("api/v1/roles", json=payload,
environ_overrides={"REMOTE_USER": "test"})
- assert resp.status_code == 200
-
- def test_get_role_permissions_forwards_to_fab(self):
- resp = self.client.get("api/v1/permissions",
environ_overrides={"REMOTE_USER": "test"})
- assert resp.status_code == 200
-
-
-class TestFABUserForwarding(TestFABforwarding):
- def _create_users(self, count, roles=None):
- # create users with defined created_on and changed_on date
- # for easy testing
- if roles is None:
- roles = []
- return [
- User(
- first_name=f"test{i}",
- last_name=f"test{i}",
- username=f"TEST_USER{i}",
- email=f"mytest@test{i}.org",
- roles=roles or [],
- created_on=timezone.parse(DEFAULT_TIME),
- changed_on=timezone.parse(DEFAULT_TIME),
- )
- for i in range(1, count + 1)
- ]
-
- def test_get_user_forwards_to_fab(self):
- users = self._create_users(1)
- session = self.app.appbuilder.get_session
- session.add_all(users)
- session.commit()
- resp = self.client.get("api/v1/users/TEST_USER1",
environ_overrides={"REMOTE_USER": "test"})
- assert resp.status_code == 200
-
- def test_get_users_forwards_to_fab(self):
- users = self._create_users(2)
- session = self.app.appbuilder.get_session
- session.add_all(users)
- session.commit()
- resp = self.client.get("api/v1/users",
environ_overrides={"REMOTE_USER": "test"})
- assert resp.status_code == 200
-
- def test_post_user_forwards_to_fab(self, autoclean_username,
autoclean_user_payload):
- response = self.client.post(
- "/api/v1/users",
- json=autoclean_user_payload,
- environ_overrides={"REMOTE_USER": "test"},
- )
- assert response.status_code == 200, response.json
-
- security_manager = self.app.appbuilder.sm
- user = security_manager.find_user(autoclean_username)
- assert user is not None
- assert user.roles == [security_manager.find_role("Public")]
-
- @pytest.mark.usefixtures("autoclean_admin_user")
- def test_patch_user_forwards_to_fab(self, autoclean_username,
autoclean_user_payload):
- autoclean_user_payload["first_name"] = "Changed"
- response = self.client.patch(
- f"/api/v1/users/{autoclean_username}",
- json=autoclean_user_payload,
- environ_overrides={"REMOTE_USER": "test"},
- )
- assert response.status_code == 200, response.json
-
- def test_delete_user_forwards_to_fab(self):
- users = self._create_users(1)
- session = self.app.appbuilder.get_session
- session.add_all(users)
- session.commit()
- resp = self.client.delete("api/v1/users/TEST_USER1",
environ_overrides={"REMOTE_USER": "test"})
- assert resp.status_code == 204
diff --git
a/tests/providers/fab/auth_manager/api_endpoints/test_role_and_permission_endpoint.py
b/tests/providers/fab/auth_manager/api_endpoints/test_role_and_permission_endpoint.py
index a91a434412..77e3107a0b 100644
---
a/tests/providers/fab/auth_manager/api_endpoints/test_role_and_permission_endpoint.py
+++
b/tests/providers/fab/auth_manager/api_endpoints/test_role_and_permission_endpoint.py
@@ -114,7 +114,7 @@ class TestGetRoleEndpoint(TestRoleEndpoint):
)
def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code):
response = self.client.get("/auth/fab/v1/roles/Admin")
- assert response.status_code == expected_status_code
+ assert response.status_code == expected_status_code, response.json
class TestGetRolesEndpoint(TestRoleEndpoint):
@@ -152,7 +152,7 @@ class TestGetRolesEndpoint(TestRoleEndpoint):
)
def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code):
response = self.client.get("/auth/fab/v1/roles")
- assert response.status_code == expected_status_code
+ assert response.status_code == expected_status_code, response.json
class TestGetRolesEndpointPaginationandFilter(TestRoleEndpoint):
@@ -214,7 +214,7 @@ class TestGetPermissionsEndpoint(TestRoleEndpoint):
)
def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code):
response = self.client.get("/auth/fab/v1/permissions")
- assert response.status_code == expected_status_code
+ assert response.status_code == expected_status_code, response.json
class TestPostRole(TestRoleEndpoint):
@@ -356,7 +356,7 @@ class TestPostRole(TestRoleEndpoint):
"actions": [{"resource": {"name": "Connections"}, "action":
{"name": "can_create"}}],
}
response = self.client.post("/auth/fab/v1/roles", json=payload)
- assert response.status_code == expected_status_code
+ assert response.status_code == expected_status_code, response.json
class TestDeleteRole(TestRoleEndpoint):
@@ -400,7 +400,7 @@ class TestDeleteRole(TestRoleEndpoint):
def test_with_auth_role_public_set(self, set_auto_role_public,
expected_status_code):
role = create_role(self.app, "mytestrole")
response = self.client.delete(f"/auth/fab/v1/roles/{role.name}")
- assert response.status_code == expected_status_code
+ assert response.status_code == expected_status_code, response.location
class TestPatchRole(TestRoleEndpoint):
@@ -589,4 +589,4 @@ class TestPatchRole(TestRoleEndpoint):
f"/auth/fab/v1/roles/{role.name}",
json={"name": "mytest"},
)
- assert response.status_code == expected_status_code
+ assert response.status_code == expected_status_code, response.json
diff --git
a/tests/providers/fab/auth_manager/api_endpoints/test_user_endpoint.py
b/tests/providers/fab/auth_manager/api_endpoints/test_user_endpoint.py
index e83d9fcf83..bc400c8a43 100644
--- a/tests/providers/fab/auth_manager/api_endpoints/test_user_endpoint.py
+++ b/tests/providers/fab/auth_manager/api_endpoints/test_user_endpoint.py
@@ -425,6 +425,7 @@ def autoclean_admin_user(configured_app,
autoclean_user_payload):
class TestPostUser(TestUserEndpoint):
def test_with_default_role(self, autoclean_username,
autoclean_user_payload):
+ self.client.application.config["AUTH_USER_REGISTRATION_ROLE"] =
"Public"
response = self.client.post(
"/auth/fab/v1/users",
json=autoclean_user_payload,
diff --git a/tests/providers/fab/auth_manager/conftest.py
b/tests/providers/fab/auth_manager/conftest.py
index d478f895bb..da18f9d6c0 100644
--- a/tests/providers/fab/auth_manager/conftest.py
+++ b/tests/providers/fab/auth_manager/conftest.py
@@ -34,7 +34,14 @@ def minimal_app_for_auth_api():
]
)
def factory():
- with conf_vars({("api", "auth_backends"):
"tests.test_utils.remote_user_api_auth_backend"}):
+ with conf_vars(
+ {
+ (
+ "api",
+ "auth_backends",
+ ):
"tests.test_utils.remote_user_api_auth_backend,airflow.api.auth.backend.session"
+ }
+ ):
_app = app.create_app(testing=True, config={"WTF_CSRF_ENABLED":
False}) # type:ignore
_app.config["AUTH_ROLE_PUBLIC"] = None
return _app
diff --git a/tests/providers/fab/auth_manager/test_fab_auth_manager.py
b/tests/providers/fab/auth_manager/test_fab_auth_manager.py
index 35e530be5a..b755afcc70 100644
--- a/tests/providers/fab/auth_manager/test_fab_auth_manager.py
+++ b/tests/providers/fab/auth_manager/test_fab_auth_manager.py
@@ -120,22 +120,24 @@ class TestFabAuthManager:
assert auth_manager.get_user() == user
+ @pytest.mark.db_test
@mock.patch.object(FabAuthManager, "get_user")
- def test_is_logged_in(self, mock_get_user, auth_manager):
+ def test_is_logged_in(self, mock_get_user, auth_manager_with_appbuilder):
user = Mock()
user.is_anonymous.return_value = True
mock_get_user.return_value = user
- assert auth_manager.is_logged_in() is False
+ assert auth_manager_with_appbuilder.is_logged_in() is False
+ @pytest.mark.db_test
@mock.patch.object(FabAuthManager, "get_user")
- def test_is_logged_in_with_inactive_user(self, mock_get_user,
auth_manager):
+ def test_is_logged_in_with_inactive_user(self, mock_get_user,
auth_manager_with_appbuilder):
user = Mock()
user.is_anonymous.return_value = False
user.is_active.return_value = True
mock_get_user.return_value = user
- assert auth_manager.is_logged_in() is False
+ assert auth_manager_with_appbuilder.is_logged_in() is False
@pytest.mark.parametrize(
"api_name, method, user_permissions, expected_result",