From 8efa2418b48afb78c844ee22c3e839caedd20179 Mon Sep 17 00:00:00 2001 From: burnettk Date: Mon, 29 May 2023 17:02:37 -0400 Subject: [PATCH] check for incompatible frontend and backend urls to save future hours --- .../spiffworkflow_backend/config/__init__.py | 39 +++++++++++++++++++ .../spiffworkflow_backend/config/default.py | 3 ++ 2 files changed, 42 insertions(+) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/config/__init__.py b/spiffworkflow-backend/src/spiffworkflow_backend/config/__init__.py index cc2a9c1f..f6ea12c3 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/config/__init__.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/config/__init__.py @@ -2,6 +2,7 @@ import os import threading import uuid +from urllib.parse import urlparse from flask.app import Flask from werkzeug.utils import ImportStringError @@ -78,6 +79,43 @@ def _set_up_tenant_specific_fields_as_list_of_strings(app: Flask) -> None: ) +# see the message in the ConfigurationError below for why we are checking this. +# we really do not want this to raise when there is not a problem, so there are lots of return statements littered throughout. +def _check_for_incompatible_frontend_and_backend_urls(app: Flask) -> None: + if not app.config.get("SPIFFWORKFLOW_BACKEND_CHECK_FRONTEND_AND_BACKEND_URL_COMPATIBILITY"): + return + + frontend_url = app.config.get("SPIFFWORKFLOW_BACKEND_URL_FOR_FRONTEND") + backend_url = app.config.get("SPIFFWORKFLOW_BACKEND_URL") + + if frontend_url is None or backend_url is None: + return + if frontend_url == "" or backend_url == "": + return + if not frontend_url.startswith("https://") or not backend_url.startswith("https://"): + return + + frontend_url_parsed = urlparse(frontend_url) + frontend_domain = frontend_url_parsed.netloc + backend_url_parsed = urlparse(backend_url) + backend_domain = backend_url_parsed.netloc + + if frontend_domain == backend_domain: + # probably backend and frontend are using different paths. + # routing by path will work just fine and won't cause any problems with setting cookies + return + + if backend_domain.endswith(frontend_domain): + return + + raise ConfigurationError( + "SPIFFWORKFLOW_BACKEND_URL_FOR_FRONTEND and SPIFFWORKFLOW_BACKEND_URL are incompatible. We need backend to set" + " cookies for frontend, so they need to be on the same domain. A common setup is to have frontend on" + " example.com and backend on api.example.com. If you do not need this functionality, you can avoid this check" + " by setting environment variable SPIFFWORKFLOW_BACKEND_CHECK_FRONTEND_AND_BACKEND_URL_COMPATIBILITY=false" + ) + + def setup_config(app: Flask) -> None: """Setup_config.""" # ensure the instance folder exists @@ -144,3 +182,4 @@ def setup_config(app: Flask) -> None: thread_local_data = threading.local() app.config["THREAD_LOCAL_DATA"] = thread_local_data _set_up_tenant_specific_fields_as_list_of_strings(app) + _check_for_incompatible_frontend_and_backend_urls(app) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py b/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py index 63f1ec7b..59bb742d 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py @@ -47,6 +47,9 @@ SPIFFWORKFLOW_BACKEND_URL_FOR_FRONTEND = environ.get( "SPIFFWORKFLOW_BACKEND_URL_FOR_FRONTEND", default="http://localhost:7001" ) SPIFFWORKFLOW_BACKEND_URL = environ.get("SPIFFWORKFLOW_BACKEND_URL", default="http://localhost:7000") +SPIFFWORKFLOW_BACKEND_CHECK_FRONTEND_AND_BACKEND_URL_COMPATIBILITY = ( + environ.get("SPIFFWORKFLOW_BACKEND_CHECK_FRONTEND_AND_BACKEND_URL_COMPATIBILITY", default="true") == "true" +) # service task connector proxy SPIFFWORKFLOW_BACKEND_CONNECTOR_PROXY_URL = environ.get( "SPIFFWORKFLOW_BACKEND_CONNECTOR_PROXY_URL", default="http://localhost:7004"