Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion homeassistant/components/http/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ def __init__(self, hass, api_password,
middlewares=[staticresource_middleware])

# This order matters
setup_real_ip(app, use_x_forwarded_for)
setup_real_ip(app, use_x_forwarded_for, trusted_networks)

if is_ban_enabled:
setup_bans(hass, app, login_threshold)
Expand Down
14 changes: 9 additions & 5 deletions homeassistant/components/http/real_ip.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,22 @@


@callback
def setup_real_ip(app, use_x_forwarded_for):
def setup_real_ip(app, use_x_forwarded_for, trusted_networks):
"""Create IP Ban middleware for the app."""
@middleware
async def real_ip_middleware(request, handler):
"""Real IP middleware."""
connected_ip = ip_address(
request.transport.get_extra_info('peername')[0])
request[KEY_REAL_IP] = connected_ip

# Only use the XFF header if enabled, present, and from a trusted proxy
if (use_x_forwarded_for and
X_FORWARDED_FOR in request.headers):
X_FORWARDED_FOR in request.headers and
any(connected_ip in trusted_network
for trusted_network in trusted_networks)):
request[KEY_REAL_IP] = ip_address(
request.headers.get(X_FORWARDED_FOR).split(',')[0])
else:
request[KEY_REAL_IP] = \
ip_address(request.transport.get_extra_info('peername')[0])

return await handler(request)

Expand Down
2 changes: 1 addition & 1 deletion tests/components/http/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def app():
"""Fixture to setup a web.Application."""
app = web.Application()
app.router.add_get('/', mock_handler)
setup_real_ip(app, False)
setup_real_ip(app, False, [])
return app


Expand Down
23 changes: 20 additions & 3 deletions tests/components/http/test_real_ip.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Test real IP middleware."""
from aiohttp import web
from aiohttp.hdrs import X_FORWARDED_FOR
from ipaddress import ip_network

from homeassistant.components.http.real_ip import setup_real_ip
from homeassistant.components.http.const import KEY_REAL_IP
Expand All @@ -15,7 +16,7 @@ async def test_ignore_x_forwarded_for(aiohttp_client):
"""Test that we get the IP from the transport."""
app = web.Application()
app.router.add_get('/', mock_handler)
setup_real_ip(app, False)
setup_real_ip(app, False, [])

mock_api_client = await aiohttp_client(app)

Expand All @@ -27,11 +28,27 @@ async def test_ignore_x_forwarded_for(aiohttp_client):
assert text != '255.255.255.255'


async def test_use_x_forwarded_for(aiohttp_client):
async def test_use_x_forwarded_for_without_trusted_proxy(aiohttp_client):
"""Test that we get the IP from the transport."""
app = web.Application()
app.router.add_get('/', mock_handler)
setup_real_ip(app, True)
setup_real_ip(app, True, [])

mock_api_client = await aiohttp_client(app)

resp = await mock_api_client.get('/', headers={
X_FORWARDED_FOR: '255.255.255.255'
})
assert resp.status == 200
text = await resp.text()
assert text != '255.255.255.255'


async def test_use_x_forwarded_for_with_trusted_proxy(aiohttp_client):
"""Test that we get the IP from the transport."""
app = web.Application()
app.router.add_get('/', mock_handler)
setup_real_ip(app, True, [ip_network('127.0.0.1')])

mock_api_client = await aiohttp_client(app)

Expand Down