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 59d592f2eb2 Add back ProxyFix Middleware for flask app builder (#49942)
59d592f2eb2 is described below

commit 59d592f2eb2e261631ef46dbd44d65acba263e25
Author: Glenn Schuurman <[email protected]>
AuthorDate: Wed Apr 30 23:26:29 2025 +0200

    Add back ProxyFix Middleware for flask app builder (#49942)
    
    * Add back ProxyFix Middleware for flask app builder
    
    Fixes Issues #49781 #49705
    
    Add back the Removed ProxyFix Middleware to allow Oauth2 authentication
    when using a reverse proxy like nginx or traefik.
    
    When not using proxyFix the redirect_url incorectly gets set to http://
    instead of the expected https://, This breaks many authentication flows,
    especially azure, which does not allow http:// redirect_urls for
    anything other than localhost.
    
    Help is needed with adjusting the configuration from webserver to
    api-server.
    
    * Add config documentation to fab provider
    
    Add the original proxy_fix documentation back into the FAB provider
    package and update the section to match fab instead of websever.
    
    * Use correct versioning scheme for provider
    
    * Fix typo in import
    
    * Bypass missing extention test
    
    ---------
    
    Co-authored-by: Glenn Schuurman <[email protected]>
---
 .../tests/unit/always/test_project_structure.py    |  1 +
 providers/fab/provider.yaml                        | 52 ++++++++++++++++++++++
 .../src/airflow/providers/fab/get_provider_info.py | 42 +++++++++++++++++
 providers/fab/src/airflow/providers/fab/www/app.py |  2 +
 .../fab/www/extensions/init_wsgi_middlewares.py    | 41 +++++++++++++++++
 5 files changed, 138 insertions(+)

diff --git a/airflow-core/tests/unit/always/test_project_structure.py 
b/airflow-core/tests/unit/always/test_project_structure.py
index af628f4b32c..a1cfba80cf6 100644
--- a/airflow-core/tests/unit/always/test_project_structure.py
+++ b/airflow-core/tests/unit/always/test_project_structure.py
@@ -138,6 +138,7 @@ class TestProjectStructure:
             
"providers/fab/tests/unit/fab/www/extensions/test_init_security.py",
             "providers/fab/tests/unit/fab/www/extensions/test_init_session.py",
             "providers/fab/tests/unit/fab/www/extensions/test_init_views.py",
+            
"providers/fab/tests/unit/fab/www/extensions/test_init_wsgi_middlewares.py",
             "providers/fab/tests/unit/fab/www/security/test_permissions.py",
             "providers/fab/tests/unit/fab/www/test_airflow_flask_app.py",
             "providers/fab/tests/unit/fab/www/test_app.py",
diff --git a/providers/fab/provider.yaml b/providers/fab/provider.yaml
index c069b3b12bd..7805ca3a0d7 100644
--- a/providers/fab/provider.yaml
+++ b/providers/fab/provider.yaml
@@ -119,6 +119,58 @@ config:
         type: integer
         example: ~
         default: "43200"
+      enable_proxy_fix:
+        description: |
+          Enable werkzeug ``ProxyFix`` middleware for reverse proxy
+        version_added: 2.1.0
+        type: boolean
+        example: ~
+        default: "False"
+      proxy_fix_x_for:
+        description: |
+          Number of values to trust for ``X-Forwarded-For``.
+          See `Werkzeug: X-Forwarded-For Proxy Fix
+          
<https://werkzeug.palletsprojects.com/en/2.3.x/middleware/proxy_fix/>`__ for 
more details.
+        version_added: 2.1.0
+        type: integer
+        example: ~
+        default: "1"
+      proxy_fix_x_proto:
+        description: |
+          Number of values to trust for ``X-Forwarded-Proto``.
+          See `Werkzeug: X-Forwarded-For Proxy Fix
+          
<https://werkzeug.palletsprojects.com/en/2.3.x/middleware/proxy_fix/>`__ for 
more details.
+        version_added: 2.1.0
+        type: integer
+        example: ~
+        default: "1"
+      proxy_fix_x_host:
+        description: |
+          Number of values to trust for ``X-Forwarded-Host``.
+          See `Werkzeug: X-Forwarded-For Proxy Fix
+          
<https://werkzeug.palletsprojects.com/en/2.3.x/middleware/proxy_fix/>`__ for 
more details.
+        version_added: 2.1.0
+        type: integer
+        example: ~
+        default: "1"
+      proxy_fix_x_port:
+        description: |
+          Number of values to trust for ``X-Forwarded-Port``.
+          See `Werkzeug: X-Forwarded-For Proxy Fix
+          
<https://werkzeug.palletsprojects.com/en/2.3.x/middleware/proxy_fix/>`__ for 
more details.
+        version_added: 2.1.0
+        type: integer
+        example: ~
+        default: "1"
+      proxy_fix_x_prefix:
+        description: |
+          Number of values to trust for ``X-Forwarded-Prefix``.
+          See `Werkzeug: X-Forwarded-For Proxy Fix
+          
<https://werkzeug.palletsprojects.com/en/2.3.x/middleware/proxy_fix/>`__ for 
more details.
+        version_added: 2.1.0
+        type: integer
+        example: ~
+        default: "1"
 
 auth-managers:
   - airflow.providers.fab.auth_manager.fab_auth_manager.FabAuthManager
diff --git a/providers/fab/src/airflow/providers/fab/get_provider_info.py 
b/providers/fab/src/airflow/providers/fab/get_provider_info.py
index 924dfca466a..6558807420a 100644
--- a/providers/fab/src/airflow/providers/fab/get_provider_info.py
+++ b/providers/fab/src/airflow/providers/fab/get_provider_info.py
@@ -79,6 +79,48 @@ def get_provider_info():
                         "example": None,
                         "default": "43200",
                     },
+                    "enable_proxy_fix": {
+                        "description": "Enable werkzeug ``ProxyFix`` 
middleware for reverse proxy\n",
+                        "version_added": "2.1.0",
+                        "type": "boolean",
+                        "example": None,
+                        "default": "False",
+                    },
+                    "proxy_fix_x_for": {
+                        "description": "Number of values to trust for 
``X-Forwarded-For``.\nSee `Werkzeug: X-Forwarded-For Proxy 
Fix\n<https://werkzeug.palletsprojects.com/en/2.3.x/middleware/proxy_fix/>`__ 
for more details.\n",
+                        "version_added": "2.1.0",
+                        "type": "integer",
+                        "example": None,
+                        "default": "1",
+                    },
+                    "proxy_fix_x_proto": {
+                        "description": "Number of values to trust for 
``X-Forwarded-Proto``.\nSee `Werkzeug: X-Forwarded-For Proxy 
Fix\n<https://werkzeug.palletsprojects.com/en/2.3.x/middleware/proxy_fix/>`__ 
for more details.\n",
+                        "version_added": "2.1.0",
+                        "type": "integer",
+                        "example": None,
+                        "default": "1",
+                    },
+                    "proxy_fix_x_host": {
+                        "description": "Number of values to trust for 
``X-Forwarded-Host``.\nSee `Werkzeug: X-Forwarded-For Proxy 
Fix\n<https://werkzeug.palletsprojects.com/en/2.3.x/middleware/proxy_fix/>`__ 
for more details.\n",
+                        "version_added": "2.1.0",
+                        "type": "integer",
+                        "example": None,
+                        "default": "1",
+                    },
+                    "proxy_fix_x_port": {
+                        "description": "Number of values to trust for 
``X-Forwarded-Port``.\nSee `Werkzeug: X-Forwarded-For Proxy 
Fix\n<https://werkzeug.palletsprojects.com/en/2.3.x/middleware/proxy_fix/>`__ 
for more details.\n",
+                        "version_added": "2.1.0",
+                        "type": "integer",
+                        "example": None,
+                        "default": "1",
+                    },
+                    "proxy_fix_x_prefix": {
+                        "description": "Number of values to trust for 
``X-Forwarded-Prefix``.\nSee `Werkzeug: X-Forwarded-For Proxy 
Fix\n<https://werkzeug.palletsprojects.com/en/2.3.x/middleware/proxy_fix/>`__ 
for more details.\n",
+                        "version_added": "2.1.0",
+                        "type": "integer",
+                        "example": None,
+                        "default": "1",
+                    },
                 },
             }
         },
diff --git a/providers/fab/src/airflow/providers/fab/www/app.py 
b/providers/fab/src/airflow/providers/fab/www/app.py
index be29f28bd67..873e7adb8f0 100644
--- a/providers/fab/src/airflow/providers/fab/www/app.py
+++ b/providers/fab/src/airflow/providers/fab/www/app.py
@@ -41,6 +41,7 @@ from airflow.providers.fab.www.extensions.init_views import (
     init_error_handlers,
     init_plugins,
 )
+from airflow.providers.fab.www.extensions.init_wsgi_middlewares import 
init_wsgi_middleware
 from airflow.providers.fab.www.utils import get_session_lifetime_config
 
 app: Flask | None = None
@@ -103,6 +104,7 @@ def create_app(enable_plugins: bool):
         init_jinja_globals(flask_app, enable_plugins=enable_plugins)
         init_xframe_protection(flask_app)
         init_airflow_session_interface(flask_app)
+        init_wsgi_middleware(flask_app)
     return flask_app
 
 
diff --git 
a/providers/fab/src/airflow/providers/fab/www/extensions/init_wsgi_middlewares.py
 
b/providers/fab/src/airflow/providers/fab/www/extensions/init_wsgi_middlewares.py
new file mode 100644
index 00000000000..bcb9d3919f6
--- /dev/null
+++ 
b/providers/fab/src/airflow/providers/fab/www/extensions/init_wsgi_middlewares.py
@@ -0,0 +1,41 @@
+# 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 typing import TYPE_CHECKING
+
+from werkzeug.middleware.proxy_fix import ProxyFix
+
+from airflow.configuration import conf
+
+if TYPE_CHECKING:
+    from flask import Flask
+
+
+def init_wsgi_middleware(flask_app: Flask) -> None:
+    """Handle X-Forwarded-* headers and base_url support."""
+    # Apply ProxyFix middleware
+    if conf.getboolean("fab", "ENABLE_PROXY_FIX"):
+        flask_app.wsgi_app = ProxyFix(  # type: ignore
+            flask_app.wsgi_app,
+            x_for=conf.getint("fab", "PROXY_FIX_X_FOR", fallback=1),
+            x_proto=conf.getint("fab", "PROXY_FIX_X_PROTO", fallback=1),
+            x_host=conf.getint("fab", "PROXY_FIX_X_HOST", fallback=1),
+            x_port=conf.getint("fab", "PROXY_FIX_X_PORT", fallback=1),
+            x_prefix=conf.getint("fab", "PROXY_FIX_X_PREFIX", fallback=1),
+        )

Reply via email to