apache-airflow-providers-fab 1.5.3__py3-none-any.whl → 2.0.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- airflow/providers/fab/LICENSE +0 -52
- airflow/providers/fab/__init__.py +3 -3
- airflow/providers/fab/auth_manager/api/auth/backend/basic_auth.py +3 -3
- airflow/providers/fab/auth_manager/api/auth/backend/kerberos_auth.py +4 -4
- airflow/providers/fab/auth_manager/api/auth/backend/session.py +1 -1
- airflow/providers/fab/auth_manager/api_endpoints/role_and_permission_endpoint.py +14 -13
- airflow/providers/fab/auth_manager/api_endpoints/user_endpoint.py +12 -12
- airflow/providers/fab/auth_manager/api_fastapi/__init__.py +16 -0
- airflow/providers/fab/auth_manager/api_fastapi/datamodels/__init__.py +16 -0
- airflow/providers/fab/auth_manager/api_fastapi/datamodels/login.py +32 -0
- airflow/providers/fab/auth_manager/api_fastapi/openapi/__init__.py +16 -0
- airflow/providers/fab/auth_manager/api_fastapi/openapi/v1-generated.yaml +152 -0
- airflow/providers/fab/auth_manager/api_fastapi/routes/__init__.py +16 -0
- airflow/providers/fab/auth_manager/api_fastapi/routes/login.py +51 -0
- airflow/providers/fab/auth_manager/api_fastapi/services/__init__.py +16 -0
- airflow/providers/fab/auth_manager/api_fastapi/services/login.py +58 -0
- airflow/providers/fab/auth_manager/cli_commands/db_command.py +2 -4
- airflow/providers/fab/auth_manager/cli_commands/user_command.py +2 -2
- airflow/providers/fab/auth_manager/cli_commands/utils.py +10 -9
- airflow/providers/fab/auth_manager/fab_auth_manager.py +231 -126
- airflow/providers/fab/auth_manager/models/__init__.py +1 -1
- airflow/providers/fab/auth_manager/models/anonymous_user.py +1 -1
- airflow/providers/fab/auth_manager/models/db.py +22 -5
- airflow/providers/fab/auth_manager/schemas/user_schema.py +1 -1
- airflow/providers/fab/auth_manager/security_manager/override.py +71 -632
- airflow/providers/fab/auth_manager/views/permissions.py +1 -1
- airflow/providers/fab/auth_manager/views/roles_list.py +1 -1
- airflow/providers/fab/auth_manager/views/user.py +1 -1
- airflow/providers/fab/auth_manager/views/user_edit.py +1 -1
- airflow/providers/fab/auth_manager/views/user_stats.py +1 -1
- airflow/providers/fab/get_provider_info.py +22 -16
- airflow/providers/fab/www/airflow_flask_app.py +31 -0
- airflow/providers/fab/www/api_connexion/__init__.py +17 -0
- airflow/providers/fab/www/api_connexion/exceptions.py +197 -0
- airflow/providers/fab/www/api_connexion/parameters.py +131 -0
- airflow/providers/fab/www/api_connexion/security.py +84 -0
- airflow/providers/fab/www/api_connexion/types.py +30 -0
- airflow/providers/fab/www/app.py +112 -0
- airflow/providers/fab/www/auth.py +350 -0
- airflow/providers/fab/www/constants.py +28 -0
- airflow/providers/fab/www/extensions/__init__.py +16 -0
- airflow/providers/fab/www/extensions/init_appbuilder.py +602 -0
- airflow/providers/fab/www/extensions/init_jinja_globals.py +82 -0
- airflow/providers/fab/www/extensions/init_manifest_files.py +61 -0
- airflow/providers/fab/www/extensions/init_security.py +61 -0
- airflow/providers/fab/www/extensions/init_session.py +64 -0
- airflow/providers/fab/www/extensions/init_views.py +177 -0
- airflow/providers/fab/www/package-lock.json +10127 -0
- airflow/providers/fab/www/package.json +81 -0
- airflow/providers/fab/www/security/__init__.py +17 -0
- airflow/providers/fab/www/security/permissions.py +126 -0
- airflow/providers/fab/www/security_appless.py +44 -0
- airflow/providers/fab/www/security_manager.py +122 -0
- airflow/providers/fab/www/session.py +41 -0
- airflow/providers/fab/www/static/css/bootstrap-theme.css +6215 -0
- airflow/providers/fab/www/static/css/flash.css +57 -0
- airflow/providers/fab/www/static/css/loading-dots.css +60 -0
- airflow/providers/fab/www/static/css/main.css +676 -0
- airflow/providers/fab/www/static/css/material-icons.css +84 -0
- airflow/providers/fab/www/static/dist/airflowDefaultTheme.feec4a4075c2f3d6ae01.css +33 -0
- airflow/providers/fab/www/static/dist/airflowDefaultTheme.feec4a4075c2f3d6ae01.js +1 -0
- airflow/providers/fab/www/static/dist/flash.137b30cff85b5588e661.css +18 -0
- airflow/providers/fab/www/static/dist/flash.137b30cff85b5588e661.js +1 -0
- airflow/providers/fab/www/static/dist/jquery-ui.min.css +5 -0
- airflow/providers/fab/www/static/dist/jquery-ui.min.js +2 -0
- airflow/providers/fab/www/static/dist/jquery-ui.min.js.LICENSE.txt +4 -0
- airflow/providers/fab/www/static/dist/loadingDots.48ab7d5b04e66f2686b0.css +18 -0
- airflow/providers/fab/www/static/dist/loadingDots.48ab7d5b04e66f2686b0.js +1 -0
- airflow/providers/fab/www/static/dist/main.ec1d38d994d72bb083cd.css +18 -0
- airflow/providers/fab/www/static/dist/main.ec1d38d994d72bb083cd.js +2 -0
- airflow/providers/fab/www/static/dist/main.ec1d38d994d72bb083cd.js.LICENSE.txt +18 -0
- airflow/providers/fab/www/static/dist/manifest.json +17 -0
- airflow/providers/fab/www/static/dist/materialIcons.57390fa60d8f61175334.css +18 -0
- airflow/providers/fab/www/static/dist/materialIcons.57390fa60d8f61175334.js +1 -0
- airflow/providers/fab/www/static/dist/moment.4d28b37c229bdfc54575.js +2 -0
- airflow/providers/fab/www/static/dist/moment.4d28b37c229bdfc54575.js.LICENSE.txt +11 -0
- airflow/providers/fab/www/static/dist/oss-licenses.json +29 -0
- airflow/providers/fab/www/static/js/datetime_utils.js +134 -0
- airflow/providers/fab/www/static/js/main.js +324 -0
- airflow/providers/fab/www/static/sort_asc.png +0 -0
- airflow/providers/fab/www/static/sort_both.png +0 -0
- airflow/providers/fab/www/static/sort_desc.png +0 -0
- airflow/providers/fab/www/templates/airflow/_messages.html +30 -0
- airflow/providers/fab/www/templates/airflow/error.html +35 -0
- airflow/providers/fab/www/templates/airflow/main.html +78 -0
- airflow/providers/fab/www/templates/airflow/traceback.html +53 -0
- airflow/providers/fab/www/templates/appbuilder/flash.html +34 -0
- airflow/providers/fab/www/templates/appbuilder/index.html +20 -0
- airflow/providers/fab/www/templates/appbuilder/navbar.html +60 -0
- airflow/providers/fab/www/templates/appbuilder/navbar_menu.html +60 -0
- airflow/providers/fab/www/templates/appbuilder/navbar_right.html +64 -0
- airflow/providers/fab/www/utils.py +272 -0
- airflow/providers/fab/www/views.py +129 -0
- airflow/providers/fab/www/webpack.config.js +213 -0
- {apache_airflow_providers_fab-1.5.3.dist-info → apache_airflow_providers_fab-2.0.0b1.dist-info}/METADATA +17 -35
- apache_airflow_providers_fab-2.0.0b1.dist-info/RECORD +122 -0
- {apache_airflow_providers_fab-1.5.3.dist-info → apache_airflow_providers_fab-2.0.0b1.dist-info}/WHEEL +1 -1
- airflow/providers/fab/auth_manager/decorators/auth.py +0 -126
- apache_airflow_providers_fab-1.5.3.dist-info/RECORD +0 -51
- /airflow/providers/fab/{auth_manager/decorators → www}/__init__.py +0 -0
- {apache_airflow_providers_fab-1.5.3.dist-info → apache_airflow_providers_fab-2.0.0b1.dist-info}/entry_points.txt +0 -0
airflow/providers/fab/LICENSE
CHANGED
@@ -199,55 +199,3 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
199
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
200
200
|
See the License for the specific language governing permissions and
|
201
201
|
limitations under the License.
|
202
|
-
|
203
|
-
============================================================================
|
204
|
-
APACHE AIRFLOW SUBCOMPONENTS:
|
205
|
-
|
206
|
-
The Apache Airflow project contains subcomponents with separate copyright
|
207
|
-
notices and license terms. Your use of the source code for the these
|
208
|
-
subcomponents is subject to the terms and conditions of the following
|
209
|
-
licenses.
|
210
|
-
|
211
|
-
|
212
|
-
========================================================================
|
213
|
-
Third party Apache 2.0 licenses
|
214
|
-
========================================================================
|
215
|
-
|
216
|
-
The following components are provided under the Apache 2.0 License.
|
217
|
-
See project link for details. The text of each license is also included
|
218
|
-
at 3rd-party-licenses/LICENSE-[project].txt.
|
219
|
-
|
220
|
-
(ALv2 License) hue v4.3.0 (https://github.com/cloudera/hue/)
|
221
|
-
(ALv2 License) jqclock v2.3.0 (https://github.com/JohnRDOrazio/jQuery-Clock-Plugin)
|
222
|
-
(ALv2 License) bootstrap3-typeahead v4.0.2 (https://github.com/bassjobsen/Bootstrap-3-Typeahead)
|
223
|
-
(ALv2 License) connexion v2.7.0 (https://github.com/zalando/connexion)
|
224
|
-
|
225
|
-
========================================================================
|
226
|
-
MIT licenses
|
227
|
-
========================================================================
|
228
|
-
|
229
|
-
The following components are provided under the MIT License. See project link for details.
|
230
|
-
The text of each license is also included at 3rd-party-licenses/LICENSE-[project].txt.
|
231
|
-
|
232
|
-
(MIT License) jquery v3.5.1 (https://jquery.org/license/)
|
233
|
-
(MIT License) dagre-d3 v0.6.4 (https://github.com/cpettitt/dagre-d3)
|
234
|
-
(MIT License) bootstrap v3.4.1 (https://github.com/twbs/bootstrap/)
|
235
|
-
(MIT License) d3-tip v0.9.1 (https://github.com/Caged/d3-tip)
|
236
|
-
(MIT License) dataTables v1.10.25 (https://datatables.net)
|
237
|
-
(MIT License) normalize.css v3.0.2 (http://necolas.github.io/normalize.css/)
|
238
|
-
(MIT License) ElasticMock v1.3.2 (https://github.com/vrcmarcos/elasticmock)
|
239
|
-
(MIT License) MomentJS v2.24.0 (http://momentjs.com/)
|
240
|
-
(MIT License) eonasdan-bootstrap-datetimepicker v4.17.49 (https://github.com/eonasdan/bootstrap-datetimepicker/)
|
241
|
-
|
242
|
-
========================================================================
|
243
|
-
BSD 3-Clause licenses
|
244
|
-
========================================================================
|
245
|
-
The following components are provided under the BSD 3-Clause license. See project links for details.
|
246
|
-
The text of each license is also included at 3rd-party-licenses/LICENSE-[project].txt.
|
247
|
-
|
248
|
-
(BSD 3 License) d3 v5.16.0 (https://d3js.org)
|
249
|
-
(BSD 3 License) d3-shape v2.1.0 (https://github.com/d3/d3-shape)
|
250
|
-
(BSD 3 License) cgroupspy 0.2.1 (https://github.com/cloudsigma/cgroupspy)
|
251
|
-
|
252
|
-
========================================================================
|
253
|
-
See 3rd-party-licenses/LICENSES-ui.txt for packages used in `/airflow/www`
|
@@ -29,11 +29,11 @@ from airflow import __version__ as airflow_version
|
|
29
29
|
|
30
30
|
__all__ = ["__version__"]
|
31
31
|
|
32
|
-
__version__ = "
|
32
|
+
__version__ = "2.0.0b1"
|
33
33
|
|
34
34
|
if packaging.version.parse(packaging.version.parse(airflow_version).base_version) < packaging.version.parse(
|
35
|
-
"
|
35
|
+
"3.0.0.dev0"
|
36
36
|
):
|
37
37
|
raise RuntimeError(
|
38
|
-
f"The package `apache-airflow-providers-fab:{__version__}` needs Apache Airflow
|
38
|
+
f"The package `apache-airflow-providers-fab:{__version__}` needs Apache Airflow 3.0.0.dev0+"
|
39
39
|
)
|
@@ -25,8 +25,8 @@ from flask import Response, current_app, request
|
|
25
25
|
from flask_appbuilder.const import AUTH_LDAP
|
26
26
|
from flask_login import login_user
|
27
27
|
|
28
|
-
from airflow.
|
29
|
-
from airflow.
|
28
|
+
from airflow.api_fastapi.app import get_auth_manager
|
29
|
+
from airflow.providers.fab.auth_manager.fab_auth_manager import FabAuthManager
|
30
30
|
|
31
31
|
if TYPE_CHECKING:
|
32
32
|
from airflow.providers.fab.auth_manager.models import User
|
@@ -46,7 +46,7 @@ def auth_current_user() -> User | None:
|
|
46
46
|
if auth is None or not auth.username or not auth.password:
|
47
47
|
return None
|
48
48
|
|
49
|
-
security_manager = cast(
|
49
|
+
security_manager = cast(FabAuthManager, get_auth_manager()).security_manager
|
50
50
|
user = None
|
51
51
|
if security_manager.auth_type == AUTH_LDAP:
|
52
52
|
user = security_manager.auth_user_ldap(auth.username, auth.password)
|
@@ -26,13 +26,13 @@ import kerberos
|
|
26
26
|
from flask import Response, current_app, g, make_response, request
|
27
27
|
from requests_kerberos import HTTPKerberosAuth
|
28
28
|
|
29
|
+
from airflow.api_fastapi.app import get_auth_manager
|
29
30
|
from airflow.configuration import conf
|
30
|
-
from airflow.providers.fab.auth_manager.
|
31
|
+
from airflow.providers.fab.auth_manager.fab_auth_manager import FabAuthManager
|
31
32
|
from airflow.utils.net import getfqdn
|
32
|
-
from airflow.www.extensions.init_auth_manager import get_auth_manager
|
33
33
|
|
34
34
|
if TYPE_CHECKING:
|
35
|
-
from airflow.auth.managers.models.base_user import BaseUser
|
35
|
+
from airflow.api_fastapi.auth.managers.models.base_user import BaseUser
|
36
36
|
|
37
37
|
log = logging.getLogger(__name__)
|
38
38
|
|
@@ -115,7 +115,7 @@ T = TypeVar("T", bound=Callable)
|
|
115
115
|
|
116
116
|
|
117
117
|
def find_user(username=None, email=None):
|
118
|
-
security_manager = cast(
|
118
|
+
security_manager = cast(FabAuthManager, get_auth_manager()).security_manager
|
119
119
|
return security_manager.find_user(username=username, email=email)
|
120
120
|
|
121
121
|
|
@@ -23,7 +23,7 @@ from typing import Any, Callable, TypeVar, cast
|
|
23
23
|
|
24
24
|
from flask import Response
|
25
25
|
|
26
|
-
from airflow.
|
26
|
+
from airflow.api_fastapi.app import get_auth_manager
|
27
27
|
|
28
28
|
CLIENT_AUTH: tuple[str, str] | Any | None = None
|
29
29
|
|
@@ -24,9 +24,8 @@ from flask import request
|
|
24
24
|
from marshmallow import ValidationError
|
25
25
|
from sqlalchemy import asc, desc, func, select
|
26
26
|
|
27
|
-
from airflow.
|
28
|
-
from airflow.
|
29
|
-
from airflow.api_connexion.security import requires_access_custom_view
|
27
|
+
from airflow.api_fastapi.app import get_auth_manager
|
28
|
+
from airflow.providers.fab.auth_manager.fab_auth_manager import FabAuthManager
|
30
29
|
from airflow.providers.fab.auth_manager.models import Action, Role
|
31
30
|
from airflow.providers.fab.auth_manager.schemas.role_and_permission_schema import (
|
32
31
|
ActionCollection,
|
@@ -35,12 +34,14 @@ from airflow.providers.fab.auth_manager.schemas.role_and_permission_schema impor
|
|
35
34
|
role_collection_schema,
|
36
35
|
role_schema,
|
37
36
|
)
|
38
|
-
from airflow.providers.fab.
|
39
|
-
from airflow.
|
40
|
-
from airflow.www.
|
37
|
+
from airflow.providers.fab.www.api_connexion.exceptions import AlreadyExists, BadRequest, NotFound
|
38
|
+
from airflow.providers.fab.www.api_connexion.parameters import check_limit, format_parameters
|
39
|
+
from airflow.providers.fab.www.api_connexion.security import requires_access_custom_view
|
40
|
+
from airflow.providers.fab.www.security import permissions
|
41
41
|
|
42
42
|
if TYPE_CHECKING:
|
43
|
-
from airflow.
|
43
|
+
from airflow.providers.fab.auth_manager.security_manager.override import FabAirflowSecurityManagerOverride
|
44
|
+
from airflow.providers.fab.www.api_connexion.types import APIResponse, UpdateMask
|
44
45
|
|
45
46
|
|
46
47
|
def _check_action_and_resource(sm: FabAirflowSecurityManagerOverride, perms: list[tuple[str, str]]) -> None:
|
@@ -59,7 +60,7 @@ def _check_action_and_resource(sm: FabAirflowSecurityManagerOverride, perms: lis
|
|
59
60
|
@requires_access_custom_view("GET", permissions.RESOURCE_ROLE)
|
60
61
|
def get_role(*, role_name: str) -> APIResponse:
|
61
62
|
"""Get role."""
|
62
|
-
security_manager = cast(
|
63
|
+
security_manager = cast(FabAuthManager, get_auth_manager()).security_manager
|
63
64
|
role = security_manager.find_role(name=role_name)
|
64
65
|
if not role:
|
65
66
|
raise NotFound(title="Role not found", detail=f"Role with name {role_name!r} was not found")
|
@@ -70,7 +71,7 @@ def get_role(*, role_name: str) -> APIResponse:
|
|
70
71
|
@format_parameters({"limit": check_limit})
|
71
72
|
def get_roles(*, order_by: str = "name", limit: int, offset: int | None = None) -> APIResponse:
|
72
73
|
"""Get roles."""
|
73
|
-
security_manager = cast(
|
74
|
+
security_manager = cast(FabAuthManager, get_auth_manager()).security_manager
|
74
75
|
session = security_manager.get_session
|
75
76
|
total_entries = session.scalars(select(func.count(Role.id))).one()
|
76
77
|
direction = desc if order_by.startswith("-") else asc
|
@@ -98,7 +99,7 @@ def get_roles(*, order_by: str = "name", limit: int, offset: int | None = None)
|
|
98
99
|
@format_parameters({"limit": check_limit})
|
99
100
|
def get_permissions(*, limit: int, offset: int | None = None) -> APIResponse:
|
100
101
|
"""Get permissions."""
|
101
|
-
security_manager = cast(
|
102
|
+
security_manager = cast(FabAuthManager, get_auth_manager()).security_manager
|
102
103
|
session = security_manager.get_session
|
103
104
|
total_entries = session.scalars(select(func.count(Action.id))).one()
|
104
105
|
query = select(Action)
|
@@ -109,7 +110,7 @@ def get_permissions(*, limit: int, offset: int | None = None) -> APIResponse:
|
|
109
110
|
@requires_access_custom_view("DELETE", permissions.RESOURCE_ROLE)
|
110
111
|
def delete_role(*, role_name: str) -> APIResponse:
|
111
112
|
"""Delete a role."""
|
112
|
-
security_manager = cast(
|
113
|
+
security_manager = cast(FabAuthManager, get_auth_manager()).security_manager
|
113
114
|
|
114
115
|
role = security_manager.find_role(name=role_name)
|
115
116
|
if not role:
|
@@ -121,7 +122,7 @@ def delete_role(*, role_name: str) -> APIResponse:
|
|
121
122
|
@requires_access_custom_view("PUT", permissions.RESOURCE_ROLE)
|
122
123
|
def patch_role(*, role_name: str, update_mask: UpdateMask = None) -> APIResponse:
|
123
124
|
"""Update a role."""
|
124
|
-
security_manager = cast(
|
125
|
+
security_manager = cast(FabAuthManager, get_auth_manager()).security_manager
|
125
126
|
body = request.json
|
126
127
|
try:
|
127
128
|
data = role_schema.load(body)
|
@@ -154,7 +155,7 @@ def patch_role(*, role_name: str, update_mask: UpdateMask = None) -> APIResponse
|
|
154
155
|
@requires_access_custom_view("POST", permissions.RESOURCE_ROLE)
|
155
156
|
def post_role() -> APIResponse:
|
156
157
|
"""Create a new role."""
|
157
|
-
security_manager = cast(
|
158
|
+
security_manager = cast(FabAuthManager, get_auth_manager()).security_manager
|
158
159
|
body = request.json
|
159
160
|
try:
|
160
161
|
data = role_schema.load(body)
|
@@ -25,9 +25,8 @@ from marshmallow import ValidationError
|
|
25
25
|
from sqlalchemy import asc, desc, func, select
|
26
26
|
from werkzeug.security import generate_password_hash
|
27
27
|
|
28
|
-
from airflow.
|
29
|
-
from airflow.
|
30
|
-
from airflow.api_connexion.security import requires_access_custom_view
|
28
|
+
from airflow.api_fastapi.app import get_auth_manager
|
29
|
+
from airflow.providers.fab.auth_manager.fab_auth_manager import FabAuthManager
|
31
30
|
from airflow.providers.fab.auth_manager.models import User
|
32
31
|
from airflow.providers.fab.auth_manager.schemas.user_schema import (
|
33
32
|
UserCollection,
|
@@ -35,19 +34,20 @@ from airflow.providers.fab.auth_manager.schemas.user_schema import (
|
|
35
34
|
user_collection_schema,
|
36
35
|
user_schema,
|
37
36
|
)
|
38
|
-
from airflow.providers.fab.
|
39
|
-
from airflow.
|
40
|
-
from airflow.www.
|
37
|
+
from airflow.providers.fab.www.api_connexion.exceptions import AlreadyExists, BadRequest, NotFound, Unknown
|
38
|
+
from airflow.providers.fab.www.api_connexion.parameters import check_limit, format_parameters
|
39
|
+
from airflow.providers.fab.www.api_connexion.security import requires_access_custom_view
|
40
|
+
from airflow.providers.fab.www.security import permissions
|
41
41
|
|
42
42
|
if TYPE_CHECKING:
|
43
|
-
from airflow.api_connexion.types import APIResponse, UpdateMask
|
44
43
|
from airflow.providers.fab.auth_manager.models import Role
|
44
|
+
from airflow.providers.fab.www.api_connexion.types import APIResponse, UpdateMask
|
45
45
|
|
46
46
|
|
47
47
|
@requires_access_custom_view("GET", permissions.RESOURCE_USER)
|
48
48
|
def get_user(*, username: str) -> APIResponse:
|
49
49
|
"""Get a user."""
|
50
|
-
security_manager = cast(
|
50
|
+
security_manager = cast(FabAuthManager, get_auth_manager()).security_manager
|
51
51
|
user = security_manager.find_user(username=username)
|
52
52
|
if not user:
|
53
53
|
raise NotFound(title="User not found", detail=f"The User with username `{username}` was not found")
|
@@ -58,7 +58,7 @@ def get_user(*, username: str) -> APIResponse:
|
|
58
58
|
@format_parameters({"limit": check_limit})
|
59
59
|
def get_users(*, limit: int, order_by: str = "id", offset: str | None = None) -> APIResponse:
|
60
60
|
"""Get users."""
|
61
|
-
security_manager = cast(
|
61
|
+
security_manager = cast(FabAuthManager, get_auth_manager()).security_manager
|
62
62
|
session = security_manager.get_session
|
63
63
|
total_entries = session.execute(select(func.count(User.id))).scalar()
|
64
64
|
direction = desc if order_by.startswith("-") else asc
|
@@ -94,7 +94,7 @@ def post_user() -> APIResponse:
|
|
94
94
|
except ValidationError as e:
|
95
95
|
raise BadRequest(detail=str(e.messages))
|
96
96
|
|
97
|
-
security_manager = cast(
|
97
|
+
security_manager = cast(FabAuthManager, get_auth_manager()).security_manager
|
98
98
|
username = data["username"]
|
99
99
|
email = data["email"]
|
100
100
|
|
@@ -137,7 +137,7 @@ def patch_user(*, username: str, update_mask: UpdateMask = None) -> APIResponse:
|
|
137
137
|
except ValidationError as e:
|
138
138
|
raise BadRequest(detail=str(e.messages))
|
139
139
|
|
140
|
-
security_manager = cast(
|
140
|
+
security_manager = cast(FabAuthManager, get_auth_manager()).security_manager
|
141
141
|
|
142
142
|
user = security_manager.find_user(username=username)
|
143
143
|
if user is None:
|
@@ -201,7 +201,7 @@ def patch_user(*, username: str, update_mask: UpdateMask = None) -> APIResponse:
|
|
201
201
|
@requires_access_custom_view("DELETE", permissions.RESOURCE_USER)
|
202
202
|
def delete_user(*, username: str) -> APIResponse:
|
203
203
|
"""Delete a user."""
|
204
|
-
security_manager = cast(
|
204
|
+
security_manager = cast(FabAuthManager, get_auth_manager()).security_manager
|
205
205
|
|
206
206
|
user = security_manager.find_user(username=username)
|
207
207
|
if user is None:
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
3
|
+
# distributed with this work for additional information
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
6
|
+
# "License"); you may not use this file except in compliance
|
7
|
+
# with the License. You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
12
|
+
# software distributed under the License is distributed on an
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14
|
+
# KIND, either express or implied. See the License for the
|
15
|
+
# specific language governing permissions and limitations
|
16
|
+
# under the License.
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
3
|
+
# distributed with this work for additional information
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
6
|
+
# "License"); you may not use this file except in compliance
|
7
|
+
# with the License. You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
12
|
+
# software distributed under the License is distributed on an
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14
|
+
# KIND, either express or implied. See the License for the
|
15
|
+
# specific language governing permissions and limitations
|
16
|
+
# under the License.
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
3
|
+
# distributed with this work for additional information
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
6
|
+
# "License"); you may not use this file except in compliance
|
7
|
+
# with the License. You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
12
|
+
# software distributed under the License is distributed on an
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14
|
+
# KIND, either express or implied. See the License for the
|
15
|
+
# specific language governing permissions and limitations
|
16
|
+
# under the License.
|
17
|
+
from __future__ import annotations
|
18
|
+
|
19
|
+
from airflow.api_fastapi.core_api.base import BaseModel
|
20
|
+
|
21
|
+
|
22
|
+
class LoginResponse(BaseModel):
|
23
|
+
"""API Token serializer for responses."""
|
24
|
+
|
25
|
+
jwt_token: str
|
26
|
+
|
27
|
+
|
28
|
+
class LoginBody(BaseModel):
|
29
|
+
"""API Token serializer for requests."""
|
30
|
+
|
31
|
+
username: str
|
32
|
+
password: str
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
3
|
+
# distributed with this work for additional information
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
6
|
+
# "License"); you may not use this file except in compliance
|
7
|
+
# with the License. You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
12
|
+
# software distributed under the License is distributed on an
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14
|
+
# KIND, either express or implied. See the License for the
|
15
|
+
# specific language governing permissions and limitations
|
16
|
+
# under the License.
|
@@ -0,0 +1,152 @@
|
|
1
|
+
openapi: 3.1.0
|
2
|
+
info:
|
3
|
+
title: FAB auth manager API
|
4
|
+
description: This is FAB auth manager API. This API is only available if the auth
|
5
|
+
manager used in the Airflow environment is FAB auth manager. This API provides
|
6
|
+
endpoints to manage users and permissions managed by the FAB auth manager.
|
7
|
+
version: 0.1.0
|
8
|
+
paths:
|
9
|
+
/token:
|
10
|
+
post:
|
11
|
+
tags:
|
12
|
+
- FabAuthManager
|
13
|
+
summary: Create Token
|
14
|
+
description: Generate a new API token.
|
15
|
+
operationId: create_token
|
16
|
+
requestBody:
|
17
|
+
content:
|
18
|
+
application/json:
|
19
|
+
schema:
|
20
|
+
$ref: '#/components/schemas/LoginBody'
|
21
|
+
required: true
|
22
|
+
responses:
|
23
|
+
'201':
|
24
|
+
description: Successful Response
|
25
|
+
content:
|
26
|
+
application/json:
|
27
|
+
schema:
|
28
|
+
$ref: '#/components/schemas/LoginResponse'
|
29
|
+
'400':
|
30
|
+
description: Bad Request
|
31
|
+
content:
|
32
|
+
application/json:
|
33
|
+
schema:
|
34
|
+
$ref: '#/components/schemas/HTTPExceptionResponse'
|
35
|
+
'401':
|
36
|
+
description: Unauthorized
|
37
|
+
content:
|
38
|
+
application/json:
|
39
|
+
schema:
|
40
|
+
$ref: '#/components/schemas/HTTPExceptionResponse'
|
41
|
+
'422':
|
42
|
+
description: Validation Error
|
43
|
+
content:
|
44
|
+
application/json:
|
45
|
+
schema:
|
46
|
+
$ref: '#/components/schemas/HTTPValidationError'
|
47
|
+
/token/cli:
|
48
|
+
post:
|
49
|
+
tags:
|
50
|
+
- FabAuthManager
|
51
|
+
summary: Create Token Cli
|
52
|
+
description: Generate a new CLI API token.
|
53
|
+
operationId: create_token_cli
|
54
|
+
requestBody:
|
55
|
+
content:
|
56
|
+
application/json:
|
57
|
+
schema:
|
58
|
+
$ref: '#/components/schemas/LoginBody'
|
59
|
+
required: true
|
60
|
+
responses:
|
61
|
+
'201':
|
62
|
+
description: Successful Response
|
63
|
+
content:
|
64
|
+
application/json:
|
65
|
+
schema:
|
66
|
+
$ref: '#/components/schemas/LoginResponse'
|
67
|
+
'400':
|
68
|
+
description: Bad Request
|
69
|
+
content:
|
70
|
+
application/json:
|
71
|
+
schema:
|
72
|
+
$ref: '#/components/schemas/HTTPExceptionResponse'
|
73
|
+
'401':
|
74
|
+
description: Unauthorized
|
75
|
+
content:
|
76
|
+
application/json:
|
77
|
+
schema:
|
78
|
+
$ref: '#/components/schemas/HTTPExceptionResponse'
|
79
|
+
'422':
|
80
|
+
description: Validation Error
|
81
|
+
content:
|
82
|
+
application/json:
|
83
|
+
schema:
|
84
|
+
$ref: '#/components/schemas/HTTPValidationError'
|
85
|
+
components:
|
86
|
+
schemas:
|
87
|
+
HTTPExceptionResponse:
|
88
|
+
properties:
|
89
|
+
detail:
|
90
|
+
anyOf:
|
91
|
+
- type: string
|
92
|
+
- type: object
|
93
|
+
title: Detail
|
94
|
+
type: object
|
95
|
+
required:
|
96
|
+
- detail
|
97
|
+
title: HTTPExceptionResponse
|
98
|
+
description: HTTPException Model used for error response.
|
99
|
+
HTTPValidationError:
|
100
|
+
properties:
|
101
|
+
detail:
|
102
|
+
items:
|
103
|
+
$ref: '#/components/schemas/ValidationError'
|
104
|
+
type: array
|
105
|
+
title: Detail
|
106
|
+
type: object
|
107
|
+
title: HTTPValidationError
|
108
|
+
LoginBody:
|
109
|
+
properties:
|
110
|
+
username:
|
111
|
+
type: string
|
112
|
+
title: Username
|
113
|
+
password:
|
114
|
+
type: string
|
115
|
+
title: Password
|
116
|
+
type: object
|
117
|
+
required:
|
118
|
+
- username
|
119
|
+
- password
|
120
|
+
title: LoginBody
|
121
|
+
description: API Token serializer for requests.
|
122
|
+
LoginResponse:
|
123
|
+
properties:
|
124
|
+
jwt_token:
|
125
|
+
type: string
|
126
|
+
title: Jwt Token
|
127
|
+
type: object
|
128
|
+
required:
|
129
|
+
- jwt_token
|
130
|
+
title: LoginResponse
|
131
|
+
description: API Token serializer for responses.
|
132
|
+
ValidationError:
|
133
|
+
properties:
|
134
|
+
loc:
|
135
|
+
items:
|
136
|
+
anyOf:
|
137
|
+
- type: string
|
138
|
+
- type: integer
|
139
|
+
type: array
|
140
|
+
title: Location
|
141
|
+
msg:
|
142
|
+
type: string
|
143
|
+
title: Message
|
144
|
+
type:
|
145
|
+
type: string
|
146
|
+
title: Error Type
|
147
|
+
type: object
|
148
|
+
required:
|
149
|
+
- loc
|
150
|
+
- msg
|
151
|
+
- type
|
152
|
+
title: ValidationError
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
3
|
+
# distributed with this work for additional information
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
6
|
+
# "License"); you may not use this file except in compliance
|
7
|
+
# with the License. You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
12
|
+
# software distributed under the License is distributed on an
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14
|
+
# KIND, either express or implied. See the License for the
|
15
|
+
# specific language governing permissions and limitations
|
16
|
+
# under the License.
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
3
|
+
# distributed with this work for additional information
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
6
|
+
# "License"); you may not use this file except in compliance
|
7
|
+
# with the License. You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
12
|
+
# software distributed under the License is distributed on an
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14
|
+
# KIND, either express or implied. See the License for the
|
15
|
+
# specific language governing permissions and limitations
|
16
|
+
# under the License.
|
17
|
+
from __future__ import annotations
|
18
|
+
|
19
|
+
from starlette import status
|
20
|
+
|
21
|
+
from airflow.api_fastapi.common.router import AirflowRouter
|
22
|
+
from airflow.api_fastapi.core_api.openapi.exceptions import create_openapi_http_exception_doc
|
23
|
+
from airflow.configuration import conf
|
24
|
+
from airflow.providers.fab.auth_manager.api_fastapi.datamodels.login import LoginBody, LoginResponse
|
25
|
+
from airflow.providers.fab.auth_manager.api_fastapi.services.login import FABAuthManagerLogin
|
26
|
+
|
27
|
+
login_router = AirflowRouter(tags=["FabAuthManager"])
|
28
|
+
|
29
|
+
|
30
|
+
@login_router.post(
|
31
|
+
"/token",
|
32
|
+
response_model=LoginResponse,
|
33
|
+
status_code=status.HTTP_201_CREATED,
|
34
|
+
responses=create_openapi_http_exception_doc([status.HTTP_400_BAD_REQUEST, status.HTTP_401_UNAUTHORIZED]),
|
35
|
+
)
|
36
|
+
def create_token(body: LoginBody) -> LoginResponse:
|
37
|
+
"""Generate a new API token."""
|
38
|
+
return FABAuthManagerLogin.create_token(body=body)
|
39
|
+
|
40
|
+
|
41
|
+
@login_router.post(
|
42
|
+
"/token/cli",
|
43
|
+
response_model=LoginResponse,
|
44
|
+
status_code=status.HTTP_201_CREATED,
|
45
|
+
responses=create_openapi_http_exception_doc([status.HTTP_400_BAD_REQUEST, status.HTTP_401_UNAUTHORIZED]),
|
46
|
+
)
|
47
|
+
def create_token_cli(body: LoginBody) -> LoginResponse:
|
48
|
+
"""Generate a new CLI API token."""
|
49
|
+
return FABAuthManagerLogin.create_token(
|
50
|
+
body=body, expiration_time_in_sec=conf.getint("api_auth", "jwt_cli_expiration_time")
|
51
|
+
)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
3
|
+
# distributed with this work for additional information
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
6
|
+
# "License"); you may not use this file except in compliance
|
7
|
+
# with the License. You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
12
|
+
# software distributed under the License is distributed on an
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14
|
+
# KIND, either express or implied. See the License for the
|
15
|
+
# specific language governing permissions and limitations
|
16
|
+
# under the License.
|