Do not process forwarded for headers for cloud requests (#54364)

This commit is contained in:
Paulus Schoutsen 2021-08-09 16:45:56 -07:00 committed by GitHub
parent a40deac714
commit 38a7bdbcf3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 34 additions and 5 deletions

View file

@ -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"],

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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