You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by ry...@apache.org on 2021/01/14 20:17:57 UTC

[airflow] branch master updated: Configurable API response (CORS) headers (#13620)

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

ryanahamilton pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/master by this push:
     new 87645b3  Configurable API response (CORS) headers (#13620)
87645b3 is described below

commit 87645b331ab1fb3f44f6958a2095b559f40646d2
Author: Ryan Hamilton <ry...@ryanahamilton.com>
AuthorDate: Thu Jan 14 15:17:43 2021 -0500

    Configurable API response (CORS) headers (#13620)
    
    * Allow setting of API response (CORS) headers via config
    
    * Fix RST syntax
    
    * Register function to only API instead of all views in app
    
    * Add missing/required property
    
    * Update spelling dictionary
---
 airflow/api_connexion/openapi/v1.yaml        |  9 +++++++++
 airflow/config_templates/config.yml          | 24 ++++++++++++++++++++++++
 airflow/config_templates/default_airflow.cfg | 12 ++++++++++++
 airflow/www/extensions/init_views.py         | 17 +++++++++++++++++
 docs/apache-airflow/security/api.rst         | 20 ++++++++++++++++++++
 docs/spelling_wordlist.txt                   |  1 +
 6 files changed, 83 insertions(+)

diff --git a/airflow/api_connexion/openapi/v1.yaml b/airflow/api_connexion/openapi/v1.yaml
index 2eabbd2..760a662 100644
--- a/airflow/api_connexion/openapi/v1.yaml
+++ b/airflow/api_connexion/openapi/v1.yaml
@@ -162,6 +162,15 @@ info:
     Note that with *Postman*, you can also generate code snippets by selecting a request and clicking on
     the **Code** button.
 
+    ## Enabling CORS
+
+    [Cross-origin resource sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
+    is a browser security feature that restricts HTTP requests that are
+    initiated from scripts running in the browser.
+
+    For details on enabling/configuring CORS, see
+    [Enabling CORS](https://airflow.apache.org/docs/apache-airflow/stable/security/api.html).
+
     # Authentication
 
     To be able to meet the requirements of many organizations, Airflow supports many authentication methods,
diff --git a/airflow/config_templates/config.yml b/airflow/config_templates/config.yml
index 1fc16e1..b128eb0 100644
--- a/airflow/config_templates/config.yml
+++ b/airflow/config_templates/config.yml
@@ -759,6 +759,30 @@
       version_added: ~
       example: /files/service-account-json
       default: ""
+    - name: access_control_allow_headers
+      description: |
+        Used in response to a preflight request to indicate which HTTP
+        headers can be used when making the actual request. This header is
+        the server side response to the browser's
+        Access-Control-Request-Headers header.
+      type: string
+      version_added: ~
+      example: ~
+      default: ""
+    - name: access_control_allow_methods
+      description: |
+        Specifies the method or methods allowed when accessing the resource.
+      type: string
+      version_added: ~
+      example: ~
+      default: ""
+    - name: access_control_allow_origin
+      description: |
+        Indicates whether the response can be shared with requesting code from the given origin.
+      type: string
+      version_added: ~
+      example: ~
+      default: ""
 - name: lineage
   description: ~
   options:
diff --git a/airflow/config_templates/default_airflow.cfg b/airflow/config_templates/default_airflow.cfg
index f03dbca..20f7906 100644
--- a/airflow/config_templates/default_airflow.cfg
+++ b/airflow/config_templates/default_airflow.cfg
@@ -408,6 +408,18 @@ google_oauth2_audience =
 # Example: google_key_path = /files/service-account-json
 google_key_path =
 
+# Used in response to a preflight request to indicate which HTTP
+# headers can be used when making the actual request. This header is
+# the server side response to the browser's
+# Access-Control-Request-Headers header.
+access_control_allow_headers =
+
+# Specifies the method or methods allowed when accessing the resource.
+access_control_allow_methods =
+
+# Indicates whether the response can be shared with requesting code from the given origin.
+access_control_allow_origin =
+
 [lineage]
 # what lineage backend to use
 backend =
diff --git a/airflow/www/extensions/init_views.py b/airflow/www/extensions/init_views.py
index f9736e6..a364773 100644
--- a/airflow/www/extensions/init_views.py
+++ b/airflow/www/extensions/init_views.py
@@ -147,6 +147,20 @@ def init_error_handlers(app: Flask):
     app.register_error_handler(404, views.circles)
 
 
+def set_cors_headers_on_response(response):
+    """Add response headers"""
+    allow_headers = conf.get('api', 'access_control_allow_headers')
+    allow_methods = conf.get('api', 'access_control_allow_methods')
+    allow_origin = conf.get('api', 'access_control_allow_origin')
+    if allow_headers is not None:
+        response.headers['Access-Control-Allow-Headers'] = allow_headers
+    if allow_methods is not None:
+        response.headers['Access-Control-Allow-Methods'] = allow_methods
+    if allow_origin is not None:
+        response.headers['Access-Control-Allow-Origin'] = allow_origin
+    return response
+
+
 def init_api_connexion(app: Flask) -> None:
     """Initialize Stable API"""
     base_path = '/api/v1'
@@ -171,6 +185,9 @@ def init_api_connexion(app: Flask) -> None:
     api_bp = connexion_app.add_api(
         specification='v1.yaml', base_path=base_path, validate_responses=True, strict_validation=True
     ).blueprint
+    # Like "api_bp.after_request", but the BP is already registered, so we have
+    # to register it in the app directly.
+    app.after_request_funcs.setdefault(api_bp.name, []).append(set_cors_headers_on_response)
     app.register_error_handler(ProblemException, common_error_handler)
     app.extensions['csrf'].exempt(api_bp)
 
diff --git a/docs/apache-airflow/security/api.rst b/docs/apache-airflow/security/api.rst
index 642843b..0c64f72 100644
--- a/docs/apache-airflow/security/api.rst
+++ b/docs/apache-airflow/security/api.rst
@@ -135,6 +135,26 @@ section of ``airflow.cfg``.
 
 Additional options to your auth backend can be configured in ``airflow.cfg``, as a new option.
 
+Enabling CORS
+---------------
+
+`Cross-origin resource sharing (CORS) <https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS>`_
+is a browser security feature that restricts HTTP requests that are initiated
+from scripts running in the browser.
+
+``Access-Control-Allow-Headers``, ``Access-Control-Allow-Methods``, and
+``Access-Control-Allow-Origin`` headers can be added by setting values for
+``access_control_allow_headers``, ``access_control_allow_methods``, and
+``access_control_allow_origin`` options in the ``[api]`` section of the
+``airflow.cfg`` file.
+
+.. code-block:: ini
+
+    [api]
+    access_control_allow_headers = origin, content-type, accept
+    access_control_allow_methods = POST, GET, OPTIONS, DELETE
+    access_control_allow_origin = https://exampleclientapp.com
+
 Page size limit
 ---------------
 
diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt
index b97a92d..ba703de 100644
--- a/docs/spelling_wordlist.txt
+++ b/docs/spelling_wordlist.txt
@@ -1070,6 +1070,7 @@ preemptible
 prefetch
 prefetched
 prefetches
+preflight
 prefork
 preloading
 prepend