From 38a7bdbcf35327de54461daf59778bc0c665a207 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 9 Aug 2021 16:45:56 -0700 Subject: [PATCH] Do not process forwarded for headers for cloud requests (#54364) --- homeassistant/components/cloud/manifest.json | 2 +- homeassistant/components/http/forwarded.py | 11 ++++++++++- homeassistant/package_constraints.txt | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/http/test_forwarded.py | 20 ++++++++++++++++++++ 6 files changed, 34 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/cloud/manifest.json b/homeassistant/components/cloud/manifest.json index 7516f32c3e1..abf73c1d54b 100644 --- a/homeassistant/components/cloud/manifest.json +++ b/homeassistant/components/cloud/manifest.json @@ -2,7 +2,7 @@ "domain": "cloud", "name": "Home Assistant Cloud", "documentation": "https://www.home-assistant.io/integrations/cloud", - "requirements": ["hass-nabucasa==0.44.0"], + "requirements": ["hass-nabucasa==0.45.1"], "dependencies": ["http", "webhook"], "after_dependencies": ["google_assistant", "alexa"], "codeowners": ["@home-assistant/cloud"], diff --git a/homeassistant/components/http/forwarded.py b/homeassistant/components/http/forwarded.py index 18bc51af1d1..9a76866ba21 100644 --- a/homeassistant/components/http/forwarded.py +++ b/homeassistant/components/http/forwarded.py @@ -63,12 +63,19 @@ def async_setup_forwarded( an HTTP 400 status code is thrown. """ + try: + from hass_nabucasa import remote # pylint: disable=import-outside-toplevel + except ImportError: + remote = None + @middleware async def forwarded_middleware( request: Request, handler: Callable[[Request], Awaitable[StreamResponse]] ) -> StreamResponse: """Process forwarded data by a reverse proxy.""" - overrides: dict[str, str] = {} + # Skip requests from Remote UI + if remote is not None and remote.is_cloud_request.get(): + return await handler(request) # Handle X-Forwarded-For forwarded_for_headers: list[str] = request.headers.getall(X_FORWARDED_FOR, []) @@ -120,6 +127,8 @@ def async_setup_forwarded( ) raise HTTPBadRequest from err + overrides: dict[str, str] = {} + # Find the last trusted index in the X-Forwarded-For list forwarded_for_index = 0 for forwarded_ip in forwarded_for: diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 2e07d0adc18..d03c4b7c4f7 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -16,7 +16,7 @@ cryptography==3.3.2 defusedxml==0.7.1 distro==1.5.0 emoji==1.2.0 -hass-nabucasa==0.44.0 +hass-nabucasa==0.45.1 home-assistant-frontend==20210809.0 httpx==0.18.2 ifaddr==0.1.7 diff --git a/requirements_all.txt b/requirements_all.txt index b71b7fcc2c0..397594de771 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -753,7 +753,7 @@ habitipy==0.2.0 hangups==0.4.14 # homeassistant.components.cloud -hass-nabucasa==0.44.0 +hass-nabucasa==0.45.1 # homeassistant.components.splunk hass_splunk==0.1.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 774721010f8..5004aa26dd7 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -431,7 +431,7 @@ habitipy==0.2.0 hangups==0.4.14 # homeassistant.components.cloud -hass-nabucasa==0.44.0 +hass-nabucasa==0.45.1 # homeassistant.components.tasmota hatasmota==0.2.20 diff --git a/tests/components/http/test_forwarded.py b/tests/components/http/test_forwarded.py index 400a1f32729..42e67416044 100644 --- a/tests/components/http/test_forwarded.py +++ b/tests/components/http/test_forwarded.py @@ -1,5 +1,6 @@ """Test real forwarded middleware.""" from ipaddress import ip_network +from unittest.mock import Mock, patch from aiohttp import web from aiohttp.hdrs import X_FORWARDED_FOR, X_FORWARDED_HOST, X_FORWARDED_PROTO @@ -441,3 +442,22 @@ async def test_x_forwarded_host_with_empty_header(aiohttp_client, caplog): assert resp.status == 400 assert "Empty value received in X-Forward-Host header" in caplog.text + + +async def test_x_forwarded_cloud(aiohttp_client, caplog): + """Test that cloud requests are not processed.""" + app = web.Application() + app.router.add_get("/", mock_handler) + async_setup_forwarded(app, True, [ip_network("127.0.0.1")]) + + mock_api_client = await aiohttp_client(app) + + with patch( + "hass_nabucasa.remote.is_cloud_request", Mock(get=Mock(return_value=True)) + ): + resp = await mock_api_client.get( + "/", headers={X_FORWARDED_FOR: "222.222.222.222", X_FORWARDED_HOST: ""} + ) + + # This request would normally fail because it's invalid, now it works. + assert resp.status == 200