This is an automated email from the ASF dual-hosted git repository.

eladkal 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 db7f92787a Deprecated kerberos auth removed (#41693)
db7f92787a is described below

commit db7f92787ab6f0e9646cc0e2a7ad5044f1d9ade8
Author: Gopal Dirisala <[email protected]>
AuthorDate: Tue Sep 17 08:48:11 2024 +0530

    Deprecated kerberos auth removed (#41693)
    
    * deprecatd kerberos auth airflow.api.auth.backend.kerberos_auth and 
airflow.auth.managers.fab.api.auth.backend.kerberos_aut removed
    
    * news fragment added
    
    * deprecatd kerberos auth airflow.api.auth.backend.kerberos_auth and 
airflow.auth.managers.fab.api.auth.backend.kerberos_aut removed
---
 airflow/api/auth/backend/kerberos_auth.py          | 182 ---------------------
 .../managers/fab/api/auth/backend/kerberos_auth.py |  43 -----
 .../auth_manager/api/auth/backend/kerberos_auth.py | 114 ++++++++++++-
 .../auth-manager/api-authentication.rst            |   2 +-
 newsfragments/41693.significant.rst                |   1 +
 .../api/auth/backend/test_kerberos_auth.py         |   5 +-
 6 files changed, 109 insertions(+), 238 deletions(-)

diff --git a/airflow/api/auth/backend/kerberos_auth.py 
b/airflow/api/auth/backend/kerberos_auth.py
deleted file mode 100644
index 100d52dd77..0000000000
--- a/airflow/api/auth/backend/kerberos_auth.py
+++ /dev/null
@@ -1,182 +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 airflow.exceptions import RemovedInAirflow3Warning
-from airflow.utils.airflow_flask_app import get_airflow_app
-
-#
-# Copyright (c) 2013, Michael Komitee
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
modification,
-# are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-#
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 
FOR
-# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES
-# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""Kerberos authentication module"""
-import logging
-import os
-from functools import wraps
-from typing import TYPE_CHECKING, Callable, NamedTuple, TypeVar, cast
-
-import kerberos
-from flask import Response, g, make_response, request
-
-from airflow.configuration import conf
-from airflow.utils.net import getfqdn
-
-if TYPE_CHECKING:
-    from airflow.auth.managers.models.base_user import BaseUser
-
-log = logging.getLogger(__name__)
-
-
-class KerberosService:
-    """Class to keep information about the Kerberos Service initialized."""
-
-    def __init__(self):
-        self.service_name = None
-
-
-class _KerberosAuth(NamedTuple):
-    return_code: int | None
-    user: str = ""
-    token: str | None = None
-
-
-# Stores currently initialized Kerberos Service
-_KERBEROS_SERVICE = KerberosService()
-
-
-def init_app(app):
-    """Initialize application with kerberos."""
-    hostname = app.config.get("SERVER_NAME")
-    if not hostname:
-        hostname = getfqdn()
-    log.info("Kerberos: hostname %s", hostname)
-
-    service = "airflow"
-
-    _KERBEROS_SERVICE.service_name = f"{service}@{hostname}"
-
-    if "KRB5_KTNAME" not in os.environ:
-        os.environ["KRB5_KTNAME"] = conf.get("kerberos", "keytab")
-
-    try:
-        log.info("Kerberos init: %s %s", service, hostname)
-        principal = kerberos.getServerPrincipalDetails(service, hostname)
-    except kerberos.KrbError as err:
-        log.warning("Kerberos: %s", err)
-    else:
-        log.info("Kerberos API: server is %s", principal)
-
-
-def _unauthorized():
-    """Indicate that authorization is required."""
-    return Response("Unauthorized", 401, {"WWW-Authenticate": "Negotiate"})
-
-
-def _forbidden():
-    return Response("Forbidden", 403)
-
-
-def _gssapi_authenticate(token) -> _KerberosAuth | None:
-    state = None
-    try:
-        return_code, state = 
kerberos.authGSSServerInit(_KERBEROS_SERVICE.service_name)
-        if return_code != kerberos.AUTH_GSS_COMPLETE:
-            return _KerberosAuth(return_code=None)
-
-        if (return_code := kerberos.authGSSServerStep(state, token)) == 
kerberos.AUTH_GSS_COMPLETE:
-            return _KerberosAuth(
-                return_code=return_code,
-                user=kerberos.authGSSServerUserName(state),
-                token=kerberos.authGSSServerResponse(state),
-            )
-        elif return_code == kerberos.AUTH_GSS_CONTINUE:
-            return _KerberosAuth(return_code=return_code)
-        return _KerberosAuth(return_code=return_code)
-    except kerberos.GSSError:
-        return _KerberosAuth(return_code=None)
-    finally:
-        if state:
-            kerberos.authGSSServerClean(state)
-
-
-T = TypeVar("T", bound=Callable)
-
-
-def requires_authentication(function: T, find_user: Callable[[str], BaseUser] 
| None = None):
-    """Decorate functions that require authentication with Kerberos."""
-    if not find_user:
-        warnings.warn(
-            "This module is deprecated. Please use "
-            
"`airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth` instead.",
-            RemovedInAirflow3Warning,
-            stacklevel=2,
-        )
-        find_user = get_airflow_app().appbuilder.sm.find_user
-
-    @wraps(function)
-    def decorated(*args, **kwargs):
-        header = request.headers.get("Authorization")
-        if header:
-            token = "".join(header.split()[1:])
-            auth = _gssapi_authenticate(token)
-            if auth.return_code == kerberos.AUTH_GSS_COMPLETE:
-                g.user = find_user(auth.user)
-                response = function(*args, **kwargs)
-                response = make_response(response)
-                if auth.token is not None:
-                    response.headers["WWW-Authenticate"] = f"negotiate 
{auth.token}"
-                return response
-            elif auth.return_code != kerberos.AUTH_GSS_CONTINUE:
-                return _forbidden()
-        return _unauthorized()
-
-    return cast(T, decorated)
-
-
-def __getattr__(name):
-    # PEP-562: Lazy loaded attributes on python modules
-    if name != "CLIENT_AUTH":
-        raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
-
-    from requests_kerberos import HTTPKerberosAuth
-
-    val = HTTPKerberosAuth(service="airflow")
-    # Store for next time
-    globals()[name] = val
-    return val
diff --git a/airflow/auth/managers/fab/api/auth/backend/kerberos_auth.py 
b/airflow/auth/managers/fab/api/auth/backend/kerberos_auth.py
deleted file mode 100644
index 838e5409f2..0000000000
--- a/airflow/auth/managers/fab/api/auth/backend/kerberos_auth.py
+++ /dev/null
@@ -1,43 +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.
-"""
-This module is deprecated.
-
-Please use 
:mod:`airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth` 
instead.
-"""
-
-from __future__ import annotations
-
-import warnings
-from typing import Any
-
-from requests_kerberos import HTTPKerberosAuth
-
-import airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth as 
fab_kerberos_auth
-from airflow.exceptions import RemovedInAirflow3Warning
-
-CLIENT_AUTH: tuple[str, str] | Any | None = HTTPKerberosAuth(service="airflow")
-
-warnings.warn(
-    "This module is deprecated. Please use 
`airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth` instead.",
-    RemovedInAirflow3Warning,
-    stacklevel=2,
-)
-
-init_app = fab_kerberos_auth.init_app
-requires_authentication = fab_kerberos_auth.requires_authentication
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 ac50aed5f0..b2c4585301 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
@@ -18,27 +18,125 @@
 from __future__ import annotations
 
 import logging
-from functools import partial
-from typing import Any, cast
+import os
+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 requests_kerberos import HTTPKerberosAuth
 
-from airflow.api.auth.backend.kerberos_auth import (
-    init_app as base_init_app,
-    requires_authentication as base_requires_authentication,
-)
+from airflow.configuration import conf
 from airflow.providers.fab.auth_manager.security_manager.override import 
FabAirflowSecurityManagerOverride
+from airflow.utils.net import getfqdn
 from airflow.www.extensions.init_auth_manager import get_auth_manager
 
+if TYPE_CHECKING:
+    from airflow.auth.managers.models.base_user import BaseUser
+
 log = logging.getLogger(__name__)
 
 CLIENT_AUTH: tuple[str, str] | Any | None = HTTPKerberosAuth(service="airflow")
 
 
+class KerberosService:
+    """Class to keep information about the Kerberos Service initialized."""
+
+    def __init__(self):
+        self.service_name = None
+
+
+class _KerberosAuth(NamedTuple):
+    return_code: int | None
+    user: str = ""
+    token: str | None = None
+
+
+# Stores currently initialized Kerberos Service
+_KERBEROS_SERVICE = KerberosService()
+
+
+def init_app(app):
+    """Initialize application with kerberos."""
+    hostname = app.config.get("SERVER_NAME")
+    if not hostname:
+        hostname = getfqdn()
+    log.info("Kerberos: hostname %s", hostname)
+
+    service = "airflow"
+
+    _KERBEROS_SERVICE.service_name = f"{service}@{hostname}"
+
+    if "KRB5_KTNAME" not in os.environ:
+        os.environ["KRB5_KTNAME"] = conf.get("kerberos", "keytab")
+
+    try:
+        log.info("Kerberos init: %s %s", service, hostname)
+        principal = kerberos.getServerPrincipalDetails(service, hostname)
+    except kerberos.KrbError as err:
+        log.warning("Kerberos: %s", err)
+    else:
+        log.info("Kerberos API: server is %s", principal)
+
+
+def _unauthorized():
+    """Indicate that authorization is required."""
+    return Response("Unauthorized", 401, {"WWW-Authenticate": "Negotiate"})
+
+
+def _forbidden():
+    return Response("Forbidden", 403)
+
+
+def _gssapi_authenticate(token) -> _KerberosAuth | None:
+    state = None
+    try:
+        return_code, state = 
kerberos.authGSSServerInit(_KERBEROS_SERVICE.service_name)
+        if return_code != kerberos.AUTH_GSS_COMPLETE:
+            return _KerberosAuth(return_code=None)
+
+        if (return_code := kerberos.authGSSServerStep(state, token)) == 
kerberos.AUTH_GSS_COMPLETE:
+            return _KerberosAuth(
+                return_code=return_code,
+                user=kerberos.authGSSServerUserName(state),
+                token=kerberos.authGSSServerResponse(state),
+            )
+        elif return_code == kerberos.AUTH_GSS_CONTINUE:
+            return _KerberosAuth(return_code=return_code)
+        return _KerberosAuth(return_code=return_code)
+    except kerberos.GSSError:
+        return _KerberosAuth(return_code=None)
+    finally:
+        if state:
+            kerberos.authGSSServerClean(state)
+
+
+T = TypeVar("T", bound=Callable)
+
+
 def find_user(username=None, email=None):
     security_manager = cast(FabAirflowSecurityManagerOverride, 
get_auth_manager().security_manager)
     return security_manager.find_user(username=username, email=email)
 
 
-init_app = base_init_app
-requires_authentication = partial(base_requires_authentication, 
find_user=find_user)
+def requires_authentication(function: T, find_user: Callable[[str], BaseUser] 
| None = find_user):
+    """Decorate functions that require authentication with Kerberos."""
+
+    @wraps(function)
+    def decorated(*args, **kwargs):
+        header = request.headers.get("Authorization")
+        if header:
+            token = "".join(header.split()[1:])
+            auth = _gssapi_authenticate(token)
+            if auth.return_code == kerberos.AUTH_GSS_COMPLETE:
+                g.user = find_user(auth.user)
+                response = function(*args, **kwargs)
+                response = make_response(response)
+                if auth.token is not None:
+                    response.headers["WWW-Authenticate"] = f"negotiate 
{auth.token}"
+                return response
+            elif auth.return_code != kerberos.AUTH_GSS_CONTINUE:
+                return _forbidden()
+        return _unauthorized()
+
+    return cast(T, decorated)
diff --git 
a/docs/apache-airflow-providers-fab/auth-manager/api-authentication.rst 
b/docs/apache-airflow-providers-fab/auth-manager/api-authentication.rst
index 0c70cb06bf..0e92330481 100644
--- a/docs/apache-airflow-providers-fab/auth-manager/api-authentication.rst
+++ b/docs/apache-airflow-providers-fab/auth-manager/api-authentication.rst
@@ -55,7 +55,7 @@ To enable Kerberos authentication, set the following in the 
configuration:
 .. code-block:: ini
 
     [api]
-    auth_backends = airflow.api.auth.backend.kerberos_auth
+    auth_backends = 
airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth
 
     [kerberos]
     keytab = <KEYTAB>
diff --git a/newsfragments/41693.significant.rst 
b/newsfragments/41693.significant.rst
new file mode 100644
index 0000000000..3479f53dea
--- /dev/null
+++ b/newsfragments/41693.significant.rst
@@ -0,0 +1 @@
+Removed deprecated auth ``airflow.api.auth.backend.kerberos_auth`` and 
``airflow.auth.managers.fab.api.auth.backend.kerberos_auth`` from 
``auth_backends``. Please use 
``airflow.providers.fab.auth_manager.api.auth.backend.kerberos_auth`` instead.
diff --git 
a/tests/providers/fab/auth_manager/api/auth/backend/test_kerberos_auth.py 
b/tests/providers/fab/auth_manager/api/auth/backend/test_kerberos_auth.py
index a49709c335..c763042e1c 100644
--- a/tests/providers/fab/auth_manager/api/auth/backend/test_kerberos_auth.py
+++ b/tests/providers/fab/auth_manager/api/auth/backend/test_kerberos_auth.py
@@ -16,9 +16,6 @@
 # under the License.
 from __future__ import annotations
 
-from airflow.api.auth.backend.kerberos_auth import (
-    init_app as base_init_app,
-)
 from tests.test_utils.compat import ignore_provider_compatibility_error
 
 with ignore_provider_compatibility_error("2.9.0+", __file__):
@@ -27,4 +24,4 @@ with ignore_provider_compatibility_error("2.9.0+", __file__):
 
 class TestKerberosAuth:
     def test_init_app(self):
-        assert init_app == base_init_app
+        init_app

Reply via email to