From afa7ca1222d47be44d40fdaa369b1fb589607caa Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 14 Nov 2021 08:11:12 -0800 Subject: [PATCH] Drop block on local proxies from HA Cloud (#59334) --- homeassistant/components/cloud/const.py | 8 -- homeassistant/components/cloud/http_api.py | 10 -- homeassistant/components/cloud/prefs.py | 47 ------- tests/components/cloud/test_http_api.py | 144 --------------------- 4 files changed, 209 deletions(-) diff --git a/homeassistant/components/cloud/const.py b/homeassistant/components/cloud/const.py index d0417e0d38d..f24f172be36 100644 --- a/homeassistant/components/cloud/const.py +++ b/homeassistant/components/cloud/const.py @@ -63,13 +63,5 @@ MODE_PROD = "production" DISPATCHER_REMOTE_UPDATE = "cloud_remote_update" -class InvalidTrustedNetworks(Exception): - """Raised when invalid trusted networks config.""" - - -class InvalidTrustedProxies(Exception): - """Raised when invalid trusted proxies config.""" - - class RequireRelink(Exception): """The skill needs to be relinked.""" diff --git a/homeassistant/components/cloud/http_api.py b/homeassistant/components/cloud/http_api.py index 64d3943dda7..c18db2ac683 100644 --- a/homeassistant/components/cloud/http_api.py +++ b/homeassistant/components/cloud/http_api.py @@ -33,8 +33,6 @@ from .const import ( PREF_GOOGLE_SECURE_DEVICES_PIN, PREF_TTS_DEFAULT_VOICE, REQUEST_TIMEOUT, - InvalidTrustedNetworks, - InvalidTrustedProxies, RequireRelink, ) @@ -42,14 +40,6 @@ _LOGGER = logging.getLogger(__name__) _CLOUD_ERRORS = { - InvalidTrustedNetworks: ( - HTTPStatus.INTERNAL_SERVER_ERROR, - "Remote UI not compatible with 127.0.0.1/::1 as a trusted network.", - ), - InvalidTrustedProxies: ( - HTTPStatus.INTERNAL_SERVER_ERROR, - "Remote UI not compatible with 127.0.0.1/::1 as trusted proxies.", - ), asyncio.TimeoutError: ( HTTPStatus.BAD_GATEWAY, "Unable to reach the Home Assistant cloud.", diff --git a/homeassistant/components/cloud/prefs.py b/homeassistant/components/cloud/prefs.py index 816ebe26d24..bb76ca3b669 100644 --- a/homeassistant/components/cloud/prefs.py +++ b/homeassistant/components/cloud/prefs.py @@ -1,8 +1,6 @@ """Preference management for cloud.""" from __future__ import annotations -from ipaddress import ip_address - from homeassistant.auth.const import GROUP_ID_ADMIN from homeassistant.auth.models import User from homeassistant.core import callback @@ -34,8 +32,6 @@ from .const import ( PREF_SHOULD_EXPOSE, PREF_TTS_DEFAULT_VOICE, PREF_USERNAME, - InvalidTrustedNetworks, - InvalidTrustedProxies, ) STORAGE_KEY = DOMAIN @@ -110,14 +106,6 @@ class CloudPreferences: if value is not UNDEFINED: prefs[key] = value - if remote_enabled is True and self._has_local_trusted_network: - prefs[PREF_ENABLE_REMOTE] = False - raise InvalidTrustedNetworks - - if remote_enabled is True and self._has_local_trusted_proxies: - prefs[PREF_ENABLE_REMOTE] = False - raise InvalidTrustedProxies - await self._save_prefs(prefs) async def async_update_google_entity_config( @@ -217,9 +205,6 @@ class CloudPreferences: if not self._prefs.get(PREF_ENABLE_REMOTE, False): return False - if self._has_local_trusted_network or self._has_local_trusted_proxies: - return False - return True @property @@ -310,38 +295,6 @@ class CloudPreferences: # an image was restored without restoring the cloud prefs. return await self._hass.auth.async_get_user(user_id) - @property - def _has_local_trusted_network(self) -> bool: - """Return if we allow localhost to bypass auth.""" - local4 = ip_address("127.0.0.1") - local6 = ip_address("::1") - - for prv in self._hass.auth.auth_providers: - if prv.type != "trusted_networks": - continue - - for network in prv.trusted_networks: - if local4 in network or local6 in network: - return True - - return False - - @property - def _has_local_trusted_proxies(self) -> bool: - """Return if we allow localhost to be a proxy and use its data.""" - if not hasattr(self._hass, "http"): - return False - - local4 = ip_address("127.0.0.1") - local6 = ip_address("::1") - - if any( - local4 in nwk or local6 in nwk for nwk in self._hass.http.trusted_proxies - ): - return True - - return False - async def _save_prefs(self, prefs): """Save preferences to disk.""" self._prefs = prefs diff --git a/tests/components/cloud/test_http_api.py b/tests/components/cloud/test_http_api.py index 947a8e0125c..42a498528ce 100644 --- a/tests/components/cloud/test_http_api.py +++ b/tests/components/cloud/test_http_api.py @@ -1,7 +1,6 @@ """Tests for the HTTP API for the cloud component.""" import asyncio from http import HTTPStatus -from ipaddress import ip_network from unittest.mock import AsyncMock, MagicMock, Mock, patch import aiohttp @@ -11,7 +10,6 @@ from hass_nabucasa.const import STATE_CONNECTED from jose import jwt import pytest -from homeassistant.auth.providers import trusted_networks as tn_auth from homeassistant.components.alexa import errors as alexa_errors from homeassistant.components.alexa.entities import LightCapabilities from homeassistant.components.cloud.const import DOMAIN, RequireRelink @@ -558,100 +556,6 @@ async def test_enabling_remote(hass, hass_ws_client, setup_api, mock_cloud_login assert len(mock_disconnect.mock_calls) == 1 -async def test_enabling_remote_trusted_networks_local4( - hass, hass_ws_client, setup_api, mock_cloud_login -): - """Test we cannot enable remote UI when trusted networks active.""" - # pylint: disable=protected-access - hass.auth._providers[ - ("trusted_networks", None) - ] = tn_auth.TrustedNetworksAuthProvider( - hass, - None, - tn_auth.CONFIG_SCHEMA( - {"type": "trusted_networks", "trusted_networks": ["127.0.0.1"]} - ), - ) - - client = await hass_ws_client(hass) - - with patch( - "hass_nabucasa.remote.RemoteUI.connect", side_effect=AssertionError - ) as mock_connect: - await client.send_json({"id": 5, "type": "cloud/remote/connect"}) - response = await client.receive_json() - - assert not response["success"] - assert response["error"]["code"] == HTTPStatus.INTERNAL_SERVER_ERROR - assert ( - response["error"]["message"] - == "Remote UI not compatible with 127.0.0.1/::1 as a trusted network." - ) - - assert len(mock_connect.mock_calls) == 0 - - -async def test_enabling_remote_trusted_networks_local6( - hass, hass_ws_client, setup_api, mock_cloud_login -): - """Test we cannot enable remote UI when trusted networks active.""" - # pylint: disable=protected-access - hass.auth._providers[ - ("trusted_networks", None) - ] = tn_auth.TrustedNetworksAuthProvider( - hass, - None, - tn_auth.CONFIG_SCHEMA( - {"type": "trusted_networks", "trusted_networks": ["::1"]} - ), - ) - - client = await hass_ws_client(hass) - - with patch( - "hass_nabucasa.remote.RemoteUI.connect", side_effect=AssertionError - ) as mock_connect: - await client.send_json({"id": 5, "type": "cloud/remote/connect"}) - response = await client.receive_json() - - assert not response["success"] - assert response["error"]["code"] == HTTPStatus.INTERNAL_SERVER_ERROR - assert ( - response["error"]["message"] - == "Remote UI not compatible with 127.0.0.1/::1 as a trusted network." - ) - - assert len(mock_connect.mock_calls) == 0 - - -async def test_enabling_remote_trusted_networks_other( - hass, hass_ws_client, setup_api, mock_cloud_login -): - """Test we can enable remote UI when trusted networks active.""" - # pylint: disable=protected-access - hass.auth._providers[ - ("trusted_networks", None) - ] = tn_auth.TrustedNetworksAuthProvider( - hass, - None, - tn_auth.CONFIG_SCHEMA( - {"type": "trusted_networks", "trusted_networks": ["192.168.0.0/24"]} - ), - ) - - client = await hass_ws_client(hass) - cloud = hass.data[DOMAIN] - - with patch("hass_nabucasa.remote.RemoteUI.connect") as mock_connect: - await client.send_json({"id": 5, "type": "cloud/remote/connect"}) - response = await client.receive_json() - - assert response["success"] - assert cloud.client.remote_autostart - - assert len(mock_connect.mock_calls) == 1 - - async def test_list_google_entities(hass, hass_ws_client, setup_api, mock_cloud_login): """Test that we can list Google entities.""" client = await hass_ws_client(hass) @@ -729,54 +633,6 @@ async def test_update_google_entity(hass, hass_ws_client, setup_api, mock_cloud_ } -async def test_enabling_remote_trusted_proxies_local4( - hass, hass_ws_client, setup_api, mock_cloud_login -): - """Test we cannot enable remote UI when trusted networks active.""" - hass.http.trusted_proxies.append(ip_network("127.0.0.1")) - - client = await hass_ws_client(hass) - - with patch( - "hass_nabucasa.remote.RemoteUI.connect", side_effect=AssertionError - ) as mock_connect: - await client.send_json({"id": 5, "type": "cloud/remote/connect"}) - response = await client.receive_json() - - assert not response["success"] - assert response["error"]["code"] == HTTPStatus.INTERNAL_SERVER_ERROR - assert ( - response["error"]["message"] - == "Remote UI not compatible with 127.0.0.1/::1 as trusted proxies." - ) - - assert len(mock_connect.mock_calls) == 0 - - -async def test_enabling_remote_trusted_proxies_local6( - hass, hass_ws_client, setup_api, mock_cloud_login -): - """Test we cannot enable remote UI when trusted networks active.""" - hass.http.trusted_proxies.append(ip_network("::1")) - - client = await hass_ws_client(hass) - - with patch( - "hass_nabucasa.remote.RemoteUI.connect", side_effect=AssertionError - ) as mock_connect: - await client.send_json({"id": 5, "type": "cloud/remote/connect"}) - response = await client.receive_json() - - assert not response["success"] - assert response["error"]["code"] == HTTPStatus.INTERNAL_SERVER_ERROR - assert ( - response["error"]["message"] - == "Remote UI not compatible with 127.0.0.1/::1 as trusted proxies." - ) - - assert len(mock_connect.mock_calls) == 0 - - async def test_list_alexa_entities(hass, hass_ws_client, setup_api, mock_cloud_login): """Test that we can list Alexa entities.""" client = await hass_ws_client(hass)