Do not process forwarded for headers for cloud requests (#54364)
This commit is contained in:
parent
a40deac714
commit
38a7bdbcf3
6 changed files with 34 additions and 5 deletions
|
@ -2,7 +2,7 @@
|
||||||
"domain": "cloud",
|
"domain": "cloud",
|
||||||
"name": "Home Assistant Cloud",
|
"name": "Home Assistant Cloud",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/cloud",
|
"documentation": "https://www.home-assistant.io/integrations/cloud",
|
||||||
"requirements": ["hass-nabucasa==0.44.0"],
|
"requirements": ["hass-nabucasa==0.45.1"],
|
||||||
"dependencies": ["http", "webhook"],
|
"dependencies": ["http", "webhook"],
|
||||||
"after_dependencies": ["google_assistant", "alexa"],
|
"after_dependencies": ["google_assistant", "alexa"],
|
||||||
"codeowners": ["@home-assistant/cloud"],
|
"codeowners": ["@home-assistant/cloud"],
|
||||||
|
|
|
@ -63,12 +63,19 @@ def async_setup_forwarded(
|
||||||
an HTTP 400 status code is thrown.
|
an HTTP 400 status code is thrown.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
from hass_nabucasa import remote # pylint: disable=import-outside-toplevel
|
||||||
|
except ImportError:
|
||||||
|
remote = None
|
||||||
|
|
||||||
@middleware
|
@middleware
|
||||||
async def forwarded_middleware(
|
async def forwarded_middleware(
|
||||||
request: Request, handler: Callable[[Request], Awaitable[StreamResponse]]
|
request: Request, handler: Callable[[Request], Awaitable[StreamResponse]]
|
||||||
) -> StreamResponse:
|
) -> StreamResponse:
|
||||||
"""Process forwarded data by a reverse proxy."""
|
"""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
|
# Handle X-Forwarded-For
|
||||||
forwarded_for_headers: list[str] = request.headers.getall(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
|
raise HTTPBadRequest from err
|
||||||
|
|
||||||
|
overrides: dict[str, str] = {}
|
||||||
|
|
||||||
# Find the last trusted index in the X-Forwarded-For list
|
# Find the last trusted index in the X-Forwarded-For list
|
||||||
forwarded_for_index = 0
|
forwarded_for_index = 0
|
||||||
for forwarded_ip in forwarded_for:
|
for forwarded_ip in forwarded_for:
|
||||||
|
|
|
@ -16,7 +16,7 @@ cryptography==3.3.2
|
||||||
defusedxml==0.7.1
|
defusedxml==0.7.1
|
||||||
distro==1.5.0
|
distro==1.5.0
|
||||||
emoji==1.2.0
|
emoji==1.2.0
|
||||||
hass-nabucasa==0.44.0
|
hass-nabucasa==0.45.1
|
||||||
home-assistant-frontend==20210809.0
|
home-assistant-frontend==20210809.0
|
||||||
httpx==0.18.2
|
httpx==0.18.2
|
||||||
ifaddr==0.1.7
|
ifaddr==0.1.7
|
||||||
|
|
|
@ -753,7 +753,7 @@ habitipy==0.2.0
|
||||||
hangups==0.4.14
|
hangups==0.4.14
|
||||||
|
|
||||||
# homeassistant.components.cloud
|
# homeassistant.components.cloud
|
||||||
hass-nabucasa==0.44.0
|
hass-nabucasa==0.45.1
|
||||||
|
|
||||||
# homeassistant.components.splunk
|
# homeassistant.components.splunk
|
||||||
hass_splunk==0.1.1
|
hass_splunk==0.1.1
|
||||||
|
|
|
@ -431,7 +431,7 @@ habitipy==0.2.0
|
||||||
hangups==0.4.14
|
hangups==0.4.14
|
||||||
|
|
||||||
# homeassistant.components.cloud
|
# homeassistant.components.cloud
|
||||||
hass-nabucasa==0.44.0
|
hass-nabucasa==0.45.1
|
||||||
|
|
||||||
# homeassistant.components.tasmota
|
# homeassistant.components.tasmota
|
||||||
hatasmota==0.2.20
|
hatasmota==0.2.20
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
"""Test real forwarded middleware."""
|
"""Test real forwarded middleware."""
|
||||||
from ipaddress import ip_network
|
from ipaddress import ip_network
|
||||||
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from aiohttp.hdrs import X_FORWARDED_FOR, X_FORWARDED_HOST, X_FORWARDED_PROTO
|
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 resp.status == 400
|
||||||
assert "Empty value received in X-Forward-Host header" in caplog.text
|
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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue